Как указано здесь, при задании whenChanged правило срабатывает при любых изменениях значений параметров, указанных в массиве.
То есть, если изменится, dev1/some_topic или dev2/another_topic, то правило сработает. Если изменится снова, то сработает ещё раз и т.д.
Что означает “изменится”? Изменит своё значение по сравнению с прошлым вызовом правила? Или произойдёт обновление топика? Во втором случае, правило будет перезапускать само себя постоянно, как я понимаю. В первом же случае, правило, видимо, выполнится два раза.
Меня такой ответ не очень устраивает. Виртуальные устройства создаются и обрабатываются самим движком wb-rules. Меня же интересует работа с реальными устройствами. К примеру, панель KNX нужно связать с устройством Modbus. Если я меняю значение в топике, соответствующему устройству Modbus, это значение отправляется в панель. Если же я меняю значение с панели, новое значение пересылается в Modbus.
Как конкретно работает whenChanged? Как оно проверяет, изменилось ли значение? Если схема усложнится, и управление нужно будет реализовать ещё с одного устройства, как поведёт себя правило?
Типично реализуется либо использованием флагов блокировки и trackMqtt либо использованием разных топиков.
Мне непонятно.
это просо hook на событие.
Может быть вам, айтишникам, это понятно. Я же привык не доверять коду, написанному айтишниками и на их айтишных языках. Как формируется событие? Если я правильно понимаю, если я записываю что-то в /on, а именно это я и делаю, присваивая dev, то значение топика не изменится, пока устройство не ответит. Но это не точно. Возможно, это зависит от драйвера. Я очень опасаюсь, что все эти правила начнут циклить и перезапускать друг друга без остановки
defineRule("Example_rule", {
whenChanged: ["dev1/some_topic", "dev2/another_topic"],
then: function (newValue, devName, cellName) {
if (devName == "dev1")
dev["dev2/another_topic"] = newValue;
else if (devName == "dev2")
dev["dev1/some_topic"] = newValue;
}
});
А можете пояснить на пальцах именно по данному коду, предложенному автором темы:
Если изменилось dev1, то
вызывается правило и в нём в dev2 записывается нужное значение;
снова вызывается данное правило, потому что в условиях его вызова указано изменение dev2. И тогда уже в dev1 снова будет записано тоже самое значение.
Далее у вас идёт речь будет ли рекурсия, но судя по всему её не будет, ибо фактического изменения dev1 уже не произойдёт. Об этом же речь?
И тогда вроде всё логично и правильно, если бы не одно но - сам по себе алгоритм уже построен с дефектом - зачем строить алгоритм так, чтобы правило срабатывало дважды на одно изменение. Т.е. получается, что критической ошибки в коде нет, он будет работать, но он составлен криво сам по себе, мне так кажется. Я бы всё же избегал таких построений. Там с точки зрения даже написания кода выбор по if бессмысленен, ибо два вызова пройдут по каждому из условий и будет эквивалентно:
Так выглядит более правильно: не важно, откуда свалилось новое значение, записать его в оба топика, так как нам надо, чтобы они были одинаковы.
Но дальше либо dev1, либо dev2 пришлет подтверждение, значение топика обновится…
И снова будет вызвана эта же функция. Фишка то в этом. Вроде и не баг, работать будет, но демонстрация того, что пользователь не понимает смысловой нагрузки кода (либо намеренно забивает на побочный эффект).
Возможно я не очень корректно выражаясь, я не хочу сказать, что код не правильный по выполнению, я хочу сказать, что сама логика программирования не позволяет сделать иначе, но как побочный эффект мы получаем рекурсивный вызов с повторным обращением к другим объектам. Если устройства 2, то 2 вызова, если 3, то 3 вызова и т.п… Это вызывает путаница и вопросы у самого пользователя.
А как в данной среде это правильно сделать, кроме например, ручного отслеживания изменений всех объектов в цикле, запускаемом раз в какое-то время - я тоже пока не знаю)
Был на объекте. Работает такая схема плохо, главным образом, потому что ничего не понятно, что происходит. Весь вечер думал, как правильно сделать. Выходит, надо напрямую работать с MQTT. Стандартными средствами не получается.
Путь в исходном состоянии значения топикA и топикБ равны 0.
Меняем, например топикA. Публикуем в него 1
Срабатывает правило, попадаем в условие - публикуем 1 в топикБ.
топикБ изменился - опять попадаем в правило, публикуем (вторая ветка условия) в топикА (который уже равен 1) то же самое значение 1.
Все, значение топикА не меняется - правило больше не срабатывает. Ну просто же, все описано в документации.
Но это не значит, конечно что вообще нельзя сделать рекурсивно зацикливающееся правило. Можно. Например из двух отдельных.
Именно такое описание я и привел в сообщении выше. Но с точки зрения программирования это бред - что-то само на себя отвечает с холостым результатом. Зачем. Кстати, если даже разбить эти вызовы на две функции, то поведение будет такое же, я уже тоже об этом думал) и я так понимаю - в данной логике работы скрипта без этой двойной отработки не избавиться. А если три устройства, то вызова будет три, или он в одной итерации сразу отработает все изменения? Об этом спрашивал автор темы, кстати, но ответа не было)
С точки зрения программистов, т.е. задумки как оно должно работать - да, логично, но для построения сложных узлов у пользователей начинается путаница) и я понимаю, что редко какая программа обходится без костылей, идеального ничего не бывает, но объективно - если у нас начинаются ложные вызовы (ложные с точки зрения сути скрипта пользователя, а не написанной программы, то значит код не совсем подходит под задачу. Всё-таки на мой взгляд очень напрашиваются доп механизмы и функции в вб-рулез)