Wb-rules 1.7 rules engine

Материал из Wiren Board
Это утверждённая версия страницы. Она же — наиболее свежая версия.
Другие языки:

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:

  1. Check if there is myVar among local variables (defined as var myVar = ...).
  2. If not, check if there is myVar in the global object (defined as myVar = ...).
  3. 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
        }
    }
});