Взаимовлияющие range

У меня есть два значения range, которые служат для управления DALI-светильниками. Назовем их range_percent и range_dali.

range_percent - это шкала для человека, от 0 до 100%. range_dali - диапазон яркости для устройства, который технологически принимает значения от 86 до 254.

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

То есть, если я делаю примерно такое:

  defineRule("change_percent_brightness", {
       whenChanged: "led/range_percent",
       then: function(newValue) {
          dev["led"]["range_dali"] = recalc_percent_to_dali(newValue);
   });
}

  defineRule("change_dali_brightness", {
       whenChanged: "led/range_dali",
       then: function(newValue) {
          dev["led"]["range_percent"] = recalc_dali_to_percent(newValue);
   });
}

Когда я меняю значение range_percent, я вижу в логах три записи:

  • Срабатывание правила change_percent_brightness
  • Срабатывание правила change_dali_brightness
  • Срабатывание правила change_percent_brightness

Отсюда вопросы. Как избавится от повторного выполнения первого шага? И второй вопрос - какие существуют best practics по взаимовлияющим значениям?

В целом, я накостылил себе решение, но оно мне не нравится. Слишком уже костыльное. Вдруг кто-то красиво такое уже решал?

Добрый день.

Два основных подхода существует.
Первый - это использование какого-то флага, устанавливаемого в одном, например, правиле и проверяемого при срабатывании другого. Используется - но не очень хорошее, как по мне.
Второй - просто выключить срабатывание правила изменить значение и снова включить. GitHub - wirenboard/wb-rules: Rule engine for Wiren Board

Во, то, что надо! Спасибо. А есть где-то описанный жизненный цикл? Чтобы понять, как правила взаимодействуют и когда какое включать выключать. Если я в первом правиле вначале сделаю disable, а потом в конце enable - то это сработает? Правила выполняются в момент изменения переменной или последоватльено? То есть какой вариант правильный:

  1. В правиле 1 я вызвал изменение значения 2. В этот момент вызвалось правило 2, отработало, вернуло управление в правило 1
  2. В правиле 1 я вызвал изменение значения 2. Сначала завершится правило 1, а потом - вызовется правило 2

Да, именно так. В контроллере используется обычный JS, функции работают асинхронно.

В таком случае можно из правила изменить соседний range без уведомления (вызова сработки правила):

getDevice('led').getControl('range_dali').setValue({value: 50, notify: false});

1 лайк

Воу!!! Это еще круче и удобнее. Спасибо!

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

Дедукция подсказывает что у автора есть 3 правило которое смотрит за изменением обоих контролов и уже управляет непосредственно устройством :sweat_smile:

1 лайк

Ну, это уже архитектурный, в общем, вопрос. :slight_smile:

Не, у меня два правила :slight_smile: Одно смотрит физическое устройство и синхронизирует движок с виртуальным. Второе - есть у виртуального, и оно синхронизирует тот же движок, но у себя с физическим. Или под третьим имеется в виду то, которое смотрит на изменение одного из них для чего-нибудь уже внешнего? Ну да. Но способ изменить число значение полосы - это норм.

У меня похожая ситуация. Управляю светом dali через панель KNX. Я воспользовался советом, поставил getControl(“lighting/dim_lvl”).setValue({ value: newValue, notify: false });
Но вот, правило не срабатывает у виртуального устройства, когда приходит телеграмма с KNX, а вот если управляешь с виртуального, то блокировка не происходит. Пробовал принудительно выключать и включать правило. Но после восстановления правила, он срабатывает.
Почему так происходит не понятно.

Я так понимаю, что это все-таки не совсем документированная функция. Штатно, вот так:

В wb-rules 2.0 появилась возможность управлять выполнением правил. Теперь функция defineRule() возвращает идентификатор созданного правила (аналогично setTimeout()/setInterval()), который можно использовать позже для выключения/включения отработки правила или принудительного запуска тела правила.

По умолчанию, все правила включены.

var myRule = defineRule({
  whenChanged: "mydev/test",
  then: function() {
    log("mydev/test changed");
  }
});

// ...

disableRule(myRule); // отключить проверку и выполнение правила
enableRule(myRule); // разрешить выполнение правила

runRule(myRule); // принудительно запустить тело правила (функцию then)
// на текущий момент не поддерживается передача аргументов в then
1 лайк

Да, совсем не факт что при ближайшем рефакторинге движка (а уже скоро) то, что не описано в документации явно - будет продолжать работать так же.

Пробовал использовать disableRule и enableRule. Эффект такой же. Для эксперимента попробовал сделать зависимость у двух виртуальных устройств. Там все нормально работает. Но вот если брать виртуальное устройство и драйвер KNX, то при изменении значения в виртуальном устройстве и применении функции включения и выключения правила, правило для параметра в устройстве KNX срабатывает. Такое впечетление, что оно срабатывает с задержкой, после выхода из правила от виртуального устройства. Если в этом правиле не включать разрешения правила для KNX, то оно не срабатывает.

Я на самом деле, хочу вообще немного переписать у себя всю логику. Сейчас по сути у меня есть связка реального и виртуального устройства с взаимозависимыми регуляторами яркости. И поверх - Apple Home, который тоже ставит яркость, ждет ответа, не получает, сбрасывает на предыдущее значение. В связке из трех зависимостей это не очень предсказуемо и долго. При этом, у Apple Home, в отличие от WB и HA, реальное изменение значения происходит в процессе движения вирутального движка, а не в момент отпускания. То есть это все порождает большую нагрузку на обмен.

Поэтому сейчас пока в голове есть такие мысли.

  1. Сделать два отдельных топика в виртуальному устройстве на уставку яркости и чтение актуального значения
  2. Убрать взаимозависимости и делать все влияния только односторонними

Я думаю, что такой подход и упростит даже отладку в случае вопросов и аварий.

Я пока ушел от WhenGhanged, использую when. Добавил еще один параметр - старое значение яркости и сравниваю старое и новое значение. В этом случае могу воздействовать на возникновение ложного вызова путем изменения старого значения яркости.