Движок правил wb-rules 1.7/en: различия между версиями
(Новая страница: «The updated wb-rules engine contains a number of important innovations regarding the logic of scripting.») |
(Новая страница: «<syntaxhighlight lang="js"> defineVirtualDevice("vdev", { ... cells: { ... mycell: { type: "value", value: "10",…») |
||
(не показано 38 промежуточных версий этого же участника) | |||
Строка 2: | Строка 2: | ||
The updated wb-rules engine contains a number of important innovations regarding the logic of scripting. | 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''' | ||
<syntaxhighlight lang="js"> | <syntaxhighlight lang="js"> | ||
var test1 = 42; | var test1 = 42; | ||
Строка 33: | Строка 33: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
''' | ''' rules2.js''' | ||
<syntaxhighlight lang="js"> | <syntaxhighlight lang="js"> | ||
test1 = 84; | |||
test2 = "Hello"; | |||
setInterval(function myFuncTwo() { | setInterval(function myFuncTwo() { | ||
Строка 45: | Строка 45: | ||
Before: | |||
<pre> | <pre> | ||
2019-01-05 17:29:50myFuncTwo called | 2019-01-05 17:29:50myFuncTwo called | ||
Строка 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. | |||
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, | |||
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. | |||
''' | '''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"; // | ps.myvar = "value"; // this value is available for users of "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 ( | wb-rules (such as defineRule, setTimeout, etc.). It can be used to pass variables or functions | ||
General field of view. | |||
<syntaxhighlight lang="js"> | <syntaxhighlight lang="js"> | ||
global.__proto__.myVar = 42; // | global.__proto__.myVar = 42; // now myVar - is a common variable for all scripts | ||
// | // 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 = ...). | ||
# | # If not, check if there is myVar in the global object (defined as myVar = ...). | ||
# | # If not, check if myVar is in the "prototype" of the global object (defined as 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. | |||
== | == 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 | |||
even if the controller loses power. These stores are useful for storing States or configurations. | |||
<syntaxhighlight lang="js"> | <syntaxhighlight lang="js"> | ||
Строка 150: | Строка 149: | ||
</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 | |||
power loss data could easily be lost). Starting with version 2.0, these values are also stored in a special permanent storage | |||
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: | |||
<syntaxhighlight lang="js"> | <syntaxhighlight lang="js"> | ||
Строка 170: | Строка 169: | ||
type: "value", | type: "value", | ||
value: "10", | value: "10", | ||
forceDefault: true // | forceDefault: true // every time the script box mycell will receive a value of 10 | ||
} | } | ||
} | } | ||
}); | }); | ||
</syntaxhighlight> | </syntaxhighlight> |
Текущая версия на 19:25, 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
Now:
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
Note
In previous versions of wb-rules, it was recommended to use loopback to isolate rules, i.e. to isolate rules. wrapping the script code into a construct:
(function() {
// script code goes here
})();
Starting from version 1.7, such a construction is usually not necessary. However, the old scripts, 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.
Warning: when using global persistent stores, a name match may occur, in this case, a hard-to-detect behavior violation is possible.
var ps = new PersistentStorage("my-global-storage", {global: true});
/// ...
ps.myvar = "value"; // this value is available for users of "my-global-storage"
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 General field of view.
global.__proto__.myVar = 42; // now myVar - is a common variable for all scripts
// the variable can be accessed from other scripts as follows
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);
The variable search rule in the first case will look like this:
- Check if there is myVar among local variables (defined as var myVar = ...).
- If not, check if there is myVar in the global object (defined as myVar = ...).
- If not, check if myVar is in the "prototype" of the global object (defined as 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.
== 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 even if the controller loses power. These stores are useful for storing States or configurations.
var ps = new PersistentStorage("my-storage", { global: true });
ps.key = "Hello World";
log(ps.key);
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 power loss data could easily be lost). Starting with version 2.0, these values are also stored in a special permanent storage 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:
defineVirtualDevice("vdev", {
...
cells: {
...
mycell: {
type: "value",
value: "10",
forceDefault: true // every time the script box mycell will receive a value of 10
}
}
});