Добрый день! Судя поуже прочитанному здесь, тема с необходимостью отдельных танцев с бубном по синхронизации каналов виртуальных устройств с каналами физических при перезапуске контроллера / рестарте wb-rules не нова. Хранилище слабо помогает здесь, поскольку состояние физического канала могло измениться за время перезагрузки/рестарта. Какие возможны подходы к решению, помимо старта при загрузке правил таймера, который через какое-то время (кстати, какое оптимально?) принудительно обновит состояние каналов?
Как вариант - после создания виртуального девайса поднять cron-правило, которое будет проверять наличие интересующего топика при помощи isControlExist каждую секунду. После инициализации запретить правило при помощи disableRule.
В качестве аргумента в IsControlExists нужно задать имя канала устройства без имени устройства и “/”. Есть ли вариант проверять, если переменной задано сразу и имя устройства, и имя канала через “/”?
Можно ли считать допустимым использование для этого вызова getControl("deviceID/ctrlID") и по получению на нем undefined делать те же выводы?
вот так: getDevice(‘devName’).isControlExists(‘cellName’)
Я не уверен, может и скрипт остановиться с ошибкой. Корректный способ - isControlExists.
Проблема в том, что каналы физических устройств заданы переменными, в которых сразу и DeviceID, и ControlID. Поэтому и желателен вариант, в котором можно сразу “скормить” это значение, а не разбирать его для каждого канала на части.
Как вариант:
var topic = 'device/control';
getDevice(topic.split('/')[0]).isControlExists(topic.split('/')[1])
Спасибо. То, что нужно. Возможно, стоит такой пример привести здесь
вклинюсь в ваш разговор
- getControl более безопасный вариант, getDevice(‘devName’).isControlExists(‘cellName’) как раз дает ошибку.
- по cron при каждом запросе, пока устройство не появится, будем получать красные строчки в логе даже на getControl (
ERROR: [rule error] Error in getting device: Device with given ID doesn't exist) . Это, кстати, очень мешает (мусорит в лог, когда это не требуется). Может 2й параметр добавите, который отключает сообщение в лог при запросе? Да и неплохо было бы добавить какое, собственно, имя устройства не существует, а то куча ошибок, а где искать неясно. getControl это тоже касается, т.к. непонятно в каком устройстве контрол не найден
код:
Summary
function makeNewVirtualControl(vdName, nameControl, typeControl){
if (getDevice(vdName) === undefined) {
defineVirtualDevice(vdName, {
title: vdName,
cells: {},
})
}
else{
log.debug("Устройство "+vdName+" уже есть.")
}
//Тут проверим есть ли уже контрол и если нет - создадим.
if (!getDevice(vdName).isControlExists(nameControl)) {
log.debug("Контрола "+nameControl+" нет, создаем.")
getDevice(vdName).addControl(nameControl, typeControl);
}
else{
log.debug("Контрол "+nameControl+" уже есть.")
}
}
function getControlTest(topic){
counter += 1;
var val = getControl(topic)
log("test.js ({}): getControl('{}') = {} [{}]", counter, topic, JSON.stringify(val), typeof val )
}
function getDeviceTest(dv,ctrl){
counter += 1;
var val = getDevice(dv).isControlExists(ctrl)
log("test.js ({}): getDevice('{}').isControlExists('{}') = {} [{}]", counter, dv, ctrl, JSON.stringify(val), typeof val )
}
makeNewVirtualControl("devName", "cellName", {type: "text", value:'Hello', readonly: true})
var counter = 0
getControlTest('devName/cellName')
getControlTest('devName/undefinedCell')
getControlTest('undefinedDev/cellName')
getControlTest('undefinedDev/undefinedCell')
getDeviceTest('devName','cellName')
getDeviceTest('devName','undefinedCell')
getDeviceTest('undefinedDev','cellName')
getDeviceTest('undefinedDev','undefinedCell')
результат:
Summary
10-03-2026 18:07:05.462 INFO: reloading file: /etc/wb-rules/test.js
10-03-2026 18:07:04.518 ERROR: [rule error] TypeError: invalid base value
duk_hobject_props.c:2000
getDeviceTest /etc/wb-rules/test.js:28
F /etc/wb-rules/test.js:44 preventsyield
10-03-2026 18:07:04.517 ERROR: [rule error] Error in getting device: Device with given ID doesn't exist
10-03-2026 18:07:04.516 INFO: [rule info] test.js (6): getDevice('devName').isControlExists('undefinedCell') = false [boolean]
10-03-2026 18:07:04.515 INFO: [rule info] test.js (5): getDevice('devName').isControlExists('cellName') = true [boolean]
10-03-2026 18:07:04.510 INFO: [rule info] test.js (4): getControl('undefinedDev/undefinedCell') = undefined [undefined]
10-03-2026 18:07:04.510 ERROR: [rule error] Error in getting device: Device with given ID doesn't exist
10-03-2026 18:07:04.510 INFO: [rule info] test.js (3): getControl('undefinedDev/cellName') = undefined [undefined]
10-03-2026 18:07:04.509 ERROR: [rule error] Error in getting device: Device with given ID doesn't exist
10-03-2026 18:07:04.509 INFO: [rule info] test.js (2): getControl('devName/undefinedCell') = undefined [undefined]
10-03-2026 18:07:04.508 ERROR: getControl(): no such control 'undefinedCell'
10-03-2026 18:07:04.507 INFO: [rule info] test.js (1): getControl('devName/cellName') = {"__cellId":"cellName","__deviceId":"devName"} [object]
10-03-2026 18:07:04.483 ERROR: [rule error] Error in getting device: Device with given ID doesn't exist
Проверил - все наоборот, получение несуществующего контрола при помощи getControl порождает ошибку (как и ожидалось), а проверка несуществующего контрола при помощи isControlExist проходит без ошибок (как и ожидалось).
По коду: мне непонятно, зачем проверять наличие виртуального девайса. Создавайте его, и все, с остальным wb-rules разберется. Или вы предполагаете, что в другом скрипте/месте создано одноименное устройство? Но в таком случае вы получите ошибку при сохранении скрипта.
у нас какие-то разные устройства? почему поведение прямо противоположное? откуда у меня такой результат?
код
Summary
function makeNewVirtualControl(vdName, nameControl, typeControl){ if (getDevice(vdName) === undefined) { defineVirtualDevice(vdName, { title: vdName, cells: {}, }) } else{ log.debug("Устройство "+vdName+" уже есть.") } //Тут проверим есть ли уже контрол и если нет - создадим. if (!getDevice(vdName).isControlExists(nameControl)) { log.debug("Контрола "+nameControl+" нет, создаем.") getDevice(vdName).addControl(nameControl, typeControl); } else{ log.debug("Контрол "+nameControl+" уже есть.") } }function getControlTest(topic){
counter += 1;
var val = getControl(topic)
log(“test.js ({}): getControl(‘{}’) = {} [{}]”, counter, topic, JSON.stringify(val), typeof val )
}
function getDeviceTest(dv,ctrl){
counter += 1;
var val = null;
try {
val = getDevice(dv).isControlExists(ctrl)
} catch (error) {
val = ‘error’
log.error(error.message, error.name, error.stack);
}
log(“test.js ({}): getDevice(‘{}’).isControlExists(‘{}’) = {} [{}]”, counter, dv, ctrl, JSON.stringify(val), typeof val )
}makeNewVirtualControl(“devName”, “cellName”, {type: “text”, value:‘Hello’, readonly: true})
var counter = 0
log(“test.js: ====== тестируем реальное устройство” )
getControlTest(‘fl0-box2_2-D18/Input 1’)
getControlTest(‘fl0-box2_2-D18/undefinedCell’)
getControlTest(‘undefinedDev/undefinedCell’)getDeviceTest(‘fl0-box2_2-D18’,‘Input 1’)
getDeviceTest(‘fl0-box2_2-D18’,‘undefinedCell’)
getDeviceTest(‘undefinedDev’,‘undefinedCell’)log(“test.js: !!! тестируем виртуальное устройство” )
getControlTest(‘devName/cellName’)
getControlTest(‘devName/undefinedCell’)
getControlTest(‘undefinedDev/undefinedCell’)
getDeviceTest(‘devName’,‘cellName’)
getDeviceTest(‘devName’,‘undefinedCell’)
getDeviceTest(‘undefinedDev’,‘undefinedCell’)
результат
Summary
11-03-2026 20:13:43.762 INFO: reloading file: /etc/wb-rules/test.js
11-03-2026 20:13:42.806 INFO: [rule info] test.js (12): getDevice('undefinedDev').isControlExists('undefinedCell') = "error" [string]
11-03-2026 20:13:42.805 ERROR: [rule error] invalid base value TypeError TypeError: invalid base value
duk_hobject_props.c:2000
getDeviceTest /etc/wb-rules/test.js:40
F /etc/wb-rules/test.js:72 preventsyield
11-03-2026 20:13:42.805 ERROR: [rule error] Error in getting device: Device with given ID doesn't exist
11-03-2026 20:13:42.804 INFO: [rule info] test.js (11): getDevice('devName').isControlExists('undefinedCell') = false [boolean]
11-03-2026 20:13:42.802 INFO: [rule info] test.js (10): getDevice('devName').isControlExists('cellName') = true [boolean]
11-03-2026 20:13:42.801 INFO: [rule info] test.js (9): getControl('undefinedDev/undefinedCell') = undefined [undefined]
11-03-2026 20:13:42.801 ERROR: [rule error] Error in getting device: Device with given ID doesn't exist
11-03-2026 20:13:42.801 INFO: [rule info] test.js (8): getControl('devName/undefinedCell') = undefined [undefined]
11-03-2026 20:13:42.800 ERROR: getControl(): no such control 'undefinedCell'
11-03-2026 20:13:42.799 INFO: [rule info] test.js (7): getControl('devName/cellName') = {"__cellId":"cellName","__deviceId":"devName"} [object]
11-03-2026 20:13:42.799 INFO: [rule info] test.js: !!!!!! тестируем виртуальное устройство
11-03-2026 20:13:42.798 INFO: [rule info] test.js (6): getDevice('undefinedDev').isControlExists('undefinedCell') = "error" [string]
11-03-2026 20:13:42.798 ERROR: [rule error] invalid base value TypeError TypeError: invalid base value
duk_hobject_props.c:2000
getDeviceTest /etc/wb-rules/test.js:40
F /etc/wb-rules/test.js:60 preventsyield
11-03-2026 20:13:42.798 ERROR: [rule error] Error in getting device: Device with given ID doesn't exist
11-03-2026 20:13:42.794 INFO: [rule info] test.js (5): getDevice('fl0-box2_2-D18').isControlExists('undefinedCell') = false [boolean]
11-03-2026 20:13:42.792 INFO: [rule info] test.js (4): getDevice('fl0-box2_2-D18').isControlExists('Input 1') = true [boolean]
11-03-2026 20:13:42.792 INFO: [rule info] test.js (3): getControl('undefinedDev/undefinedCell') = undefined [undefined]
11-03-2026 20:13:42.788 ERROR: [rule error] Error in getting device: Device with given ID doesn't exist
11-03-2026 20:13:42.786 INFO: [rule info] test.js (2): getControl('fl0-box2_2-D18/undefinedCell') = undefined [undefined]
11-03-2026 20:13:42.786 ERROR: getControl(): no such control 'undefinedCell'
11-03-2026 20:13:42.784 INFO: [rule info] test.js (1): getControl('fl0-box2_2-D18/Input 1') = {"__cellId":"Input 1","__deviceId":"fl0-box2_2-D18"} [object]
11-03-2026 20:13:42.781 INFO: [rule info] test.js: ====== тестируем реальное устройство
11-03-2026 20:13:42.774 ERROR: [rule error] Error in getting device: Device with given ID doesn't exist
1.в этом коде - для теста.
2.чтобы не получать краши, если устройство еще не успело создаться при загрузке.
3.поведение для всех устройств должно быть одинаковым и предсказуемым
если вы с такими ситуациями не сталкивались, это не значит, что никому это не нужно… например, я создаю клоны счетчиков с увеличенным коэффициентом трансформации, а потом еще до кучи мне нужно суммировать эти показания в один общий счетчик и считать суммарное потребление. т.е создаю на каждый реальный счетчик по виртуальному, а потом создаю еще один виртуальный счетчик, который суммирует 3 виртуальных.
Я проверял наличие контролов у физических устройств. Проверка для виртуальных устройств, на мой взгляд, смысла не имеет - вы же всегда знаете, создали вы устройство, или еще нет.
Если создание виртуального устройства находится выше по коду, то оно точно будет создано к моменту проверки - движок правил однопоточный.
а если создание виртуального устройства находится в соседнем скрипте?
каков порядок запуска скриптов правил?
или виртуальное устройство создается не в процессе исполнения скрипта, а ждет, пока физическое устройство появится, чтобы создать его клон.
я тоже проверил на физическом, получил результат противоположный вашему. Почему?
это лишь ваш взгляд…
в документации:
Функция defineVirtualDevice() возвращает объект, представляющей собой виртуальное устройство. Также этот объект можно получить с помощью глобальной функции getDevice(<id девайса>). Аналогично, можно получить объект контрола при помощи глобальной функции getControl(<id девайса>/<id контрола>)
...
Так как при попытке установить значения контролов не виртуальных (внешних) девайсов возникает исключение — для проверки на принадлежность девайса можно использовать метод isVirtual()
кроме “установить значения контролов” отличий не нашел, в остальном одни только сходства.
поведение системы при использовании одной и той же функции для физического и виртуального устройства должно быть единообразным и предсказуемым.
алфавитный, т.е. если вы назовете файлы 1.js, 2.js, то они так и будут обработаны
создается сразу, и прямо в следующей строчке можно его использовать
Спорно. В случае физических устройств топики формируют драйверы, и возникает асинхронность. А в случае виртуальных - сам движок правил, и там все предсказуемо.
Надо нам это воспроизвести: опишите, что за физическое устройство, минимизируйте скрипт до одной строчки, опишите действия пошагово либо запишите скринкаст.
это нигде не описано.
я имел ввиду, что я не сразу создаю виртуальное устройство, а жду, пока появится физическое, чтобы с него скопировать наборы контролов и параметры этих контролов.
тогда название функций сделайте разными для физических и виртуальных устройств.
для физических вообще было бы правильным сделать какой-то признак, по которому можно узнать, что устройство полностью завершило все процессы инициализации драйвером и можно обращаться ко всем контролам.
код, лог и диагностический архив публиковал здесь. физическое устройство WB-MDM3.
ваше требование минимизировать скрипт до одной строчки выглядит абсурдным и как нежелание разбираться в проблеме.
Почему на виртуальном устройстве результат противоположный вашему?
могу дать удаленный доступ к устройству