Сопоставление каналов виртуальных устройств физическим после перезагрузки

Добрый день! Судя поуже прочитанному здесь, тема с необходимостью отдельных танцев с бубном по синхронизации каналов виртуальных устройств с каналами физических при перезапуске контроллера / рестарте 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])

Спасибо. То, что нужно. Возможно, стоит такой пример привести здесь

вклинюсь в ваш разговор

  1. getControl более безопасный вариант, getDevice(‘devName’).isControlExists(‘cellName’) как раз дает ошибку.
  2. по 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
2 лайка

Проверил - все наоборот, получение несуществующего контрола при помощи 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 виртуальных.

приложен диагностический архив, доступен только сотрудникам поддержки
(696.8 KB)

Я проверял наличие контролов у физических устройств. Проверка для виртуальных устройств, на мой взгляд, смысла не имеет - вы же всегда знаете, создали вы устройство, или еще нет.

Если создание виртуального устройства находится выше по коду, то оно точно будет создано к моменту проверки - движок правил однопоточный.

а если создание виртуального устройства находится в соседнем скрипте?
каков порядок запуска скриптов правил?
или виртуальное устройство создается не в процессе исполнения скрипта, а ждет, пока физическое устройство появится, чтобы создать его клон.

я тоже проверил на физическом, получил результат противоположный вашему. Почему?

это лишь ваш взгляд…

в документации:

Функция defineVirtualDevice() возвращает объект, представляющей собой виртуальное устройство. Также этот объект можно получить с помощью глобальной функции getDevice(<id девайса>). Аналогично, можно получить объект контрола при помощи глобальной функции getControl(<id девайса>/<id контрола>)
...
Так как при попытке установить значения контролов не виртуальных (внешних) девайсов возникает исключение — для проверки на принадлежность девайса можно использовать метод isVirtual()

кроме “установить значения контролов” отличий не нашел, в остальном одни только сходства.

поведение системы при использовании одной и той же функции для физического и виртуального устройства должно быть единообразным и предсказуемым.

1 лайк

алфавитный, т.е. если вы назовете файлы 1.js, 2.js, то они так и будут обработаны

создается сразу, и прямо в следующей строчке можно его использовать

Спорно. В случае физических устройств топики формируют драйверы, и возникает асинхронность. А в случае виртуальных - сам движок правил, и там все предсказуемо.

Надо нам это воспроизвести: опишите, что за физическое устройство, минимизируйте скрипт до одной строчки, опишите действия пошагово либо запишите скринкаст.

это нигде не описано.

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

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

код, лог и диагностический архив публиковал здесь. физическое устройство WB-MDM3.
ваше требование минимизировать скрипт до одной строчки выглядит абсурдным и как нежелание разбираться в проблеме.

Почему на виртуальном устройстве результат противоположный вашему?

могу дать удаленный доступ к устройству