Совместимость скриптов при обновлении wb-rules
This is the approved revision of this page, as well as being the most recent.
Обновление до версии 2.2
С версии 2.2 стали более строго проверяться типы устанавливаемых значений для контролов:
- Раньше для установки признака включено/выключено для switch и состояний pushbutton можно было присваивать значение 1 или 0 — теперь только true/false.
- Раньше контролу типа text можно было присвоить число и оно автоматически конвертировалось текст — теперь только текст. Если нужно записать число, то используйте
(val).toString()
для конвертации. - Раньше для передачи в контролы типа value и его подтипов (Temperature, Power, Voltage и прочие) значений допускалось указывать значения в кавычках — теперь нужно указывать только число.
Если в коде есть ошибка, то выполнение скрипта останавливается и в логи добавляются записи вида:
ERROR: control wb-mr3_30/K1 SetValue() error: can't convert control value '1' (type float64) to datatype 'switch' ERROR: control system/Reboot SetValue() error: can't convert control value '1' (type float64) to datatype 'pushbutton' ERROR: control status/someStatus SetValue() error: can't convert control value '-1.47' (type float64) to datatype 'text'
Раньше писали так:
dev["wb-mr3_30"]["K1"] = 1 // включение
dev["status"]["someStatus"] = -1.47 // float
dev["temperature"]["value"] = "36.6" // text
Теперь только так:
dev["wb-mr3_30"]["K1"] = true // включение
dev["status"]["someStatus"] = (-1.47).toString() // text
dev["temperature"]["value"] = 36.6 // float
Обновление до версии 1.7
Начиная с версии wb-rules 1.7, локальные переменные и функции, объявленные в файле сценария не видны в других сценариях. Таким образом, каждый сценарий может определять свои функции и переменные без риска изменить поведение других сценариев.
В качестве примера приведём два сценария, одновременно запускаемых в движке правил. Каждый сценарий определяет переменные и функции. В предыдущих версиях wb-rules обращение к переменной, изменяемой в нескольких файлах сценариев, может привести к неопределённому поведению. В версиях, начиная с 1.7, поведение строго определено и такое же, как будто сценарий единственный в системе.
Сценарий 1 (rules1.js):
var test1 = 42;
setInterval(function myFuncOne() {
log("myFuncOne called");
log("test1: {}", test1);
log("test2: {}", test2);
}, 5000);
Сценарий 2 (rules2.js):
var test1 = 84;
var test2 = "Hello";
setInterval(function myFuncTwo() {
log("myFuncTwo called");
log("test1: {}, test2: {}", test1, test2);
}, 5000);
Было:
2019-01-05 17:29:50 myFuncTwo called 2019-01-05 17:29:50 test1: 84, test2: Hello 2019-01-05 17:29:50 myFuncOne called 2019-01-05 17:29:50 test1: 84 2019-01-05 17:29:50 test2: Hello
Стало:
2019-01-05 17:28:42 myFuncTwo called 2019-01-05 17:28:42 test1: 84, test2: Hello 2019-01-05 17:28:42 myFuncOne called 2019-01-05 17:28:42 test1: 42 2019-01-05 17:28:42 ECMAScript error: ReferenceError: identifier 'test2' undefined duk_js_var.c:1232 myFuncOne /etc/wb-rules/rules1.js:6 preventsyield
Возможные способы решения проблемы:
Способ 1
Самый простой способ: перенести всю логику, которая использует доступ к переменной в другм файле в тот же файл, где определена переменная. Т.е. на примере приведённых выше правил нужно перенести всё в один файл rules1.js
var test1 = 42;
var test2 = "Hello";
setInterval(function myFuncTwo() {
log("myFuncTwo called");
log("test1: {}, test2: {}", test1, test2);
}, 5000);
setInterval(function myFuncOne() {
log("myFuncOne called");
log("test1: {}", test1);
log("test2: {}", test2);
}, 5000);
Способ 2
Следующий способ заключается в использовании глобального постоянного хранилища (PersistentStorage) ====
Внимание: при использовании глобальных постоянных хранилищ может произойти совпадение имён, в этом случае возможно труднообнаруживаемое нарушение поведения.
Вышеприведённый пример можно исправить следующим образом:
Сценарий 1 (rules1.js):
var test1 = 42;
var ps = new PersistentStorage("my-global-storage", {global: true});
ps.test1 = test1;
setInterval(function myFuncOne() {
log("myFuncOne called");
log("test1: {}", test1);
log("test2: {}", ps.test2);
}, 5000);
Сценарий 2 (rules2.js):
var test2 = "Hello";
var ps = new PersistentStorage("my-global-storage", {global: true});
ps.test2 = test2;
setInterval(function myFuncTwo() {
log("myFuncTwo called");
log("test1: {}, test2: {}", ps.test1, test2);
}, 5000);
Способ 3
"Грязный" способ, который использует прототип глобального объекта - использовать этот способ не рекомендуется из-за возможного замусоривания глобального пространства пользовательскими данными.
Исправленная версия:
Сценарий 1 (rules1.js):
global.__proto__.test1 = 42;
setInterval(function myFuncOne() {
log("myFuncOne called");
log("test1: {}", global.__proto__.test1);
log("test2: {}", global.__proto__.test2);
}, 5000);
Сценарий 2 (rules2.js):
global.__proto__.test2 = "Hello";
setInterval(function myFuncTwo() {
log("myFuncTwo called");
log("test1: {}, test2: {}", global.__proto__.test1, global.__proto__.test2);
}, 5000);