Отработка правила через раз

Здравствуйте. Помогите, пожалуйста, разобраться, почему это простое правило отрабатывает при переключении свитча “Test” только каждый второй раз?

defineVirtualDevice("testRule", {
  title: "testRule",
  cells: {
    "Message": {
      type: "text",
      value: "",
      readonly: false
    },
    "Test": {
      type: "switch",
      value: false,
      readonly: false
    }
  }
});

defineRule("sendMessage", {
  whenChanged: "testRule/Message",
  then: function (newValue, devName, cellName) {
    if (newValue){
      log('Sending a message:' + newValue);
      dev["testRule/Message"] = "";
    }
  }
});

defineRule("test", {
  whenChanged: "testRule/Test",
  then: function (newValue, devName, cellName) {
    var message = 'dev: ' + devName + '; cell: ' + cellName + '; val: ' + newValue;
    log(message);
    dev["testRule/Message"] = message;
  }
});

Добрый день!

Судя по логике, после сработки переменная не сбрасывается и по этому сработка не всегда идет.
Перед присвоением Message добавьте строку, которая обнуляет переменную.

Что-то не до конца понимаю, какая переменная не сбрасывается?
Если я пишу:

var message = '';
message = 'dev: ' + devName + '; cell: ' + cellName + '; val: ' + newValue;

ничего не меняется.
Если:

dev["testRule/Message"] = '';
dev["testRule/Message"] = message;

то дело до правила sendMessage вообще не доходит.

Добрый день!
Проблема в том, что whenChanged не срабатывает, если вы присваиваете в dev["testRule/Message"] то же значение, которое там уже было. Именно это и происходит в вашем случае: при повторном нажатии на свитч Test с тем же значением Message обновляется на то же самое значение, и whenChanged: "testRule/Message" не срабатывает.

Попрорбуйте такой вариант, при такой конструкции работает корректно

defineRule("test", {
  whenChanged: "testRule/Test",
  then: function (newValue, devName, cellName) {
    var message = 'dev: ' + devName + '; cell: ' + cellName + '; val: ' + newValue;
    log(message);
    dev["testRule/Message"] = "";          // сброс перед присвоением
    dev["testRule/Message"] = message;     // установка нового значения
  }
});

Смотрите мой код. В правиле "sendMessage", при изменении "testRule/Message" выполняется код внутри if (newValue){.... Там же есть строка, обнуляющая "testRule/Message".
К тому же, т.к. "testRule/Test" - это переключатель и он публикует то false, то true, в "testRule/Message" не отправляется два одинаковых сообщения.
В логе:

dev: testRule; cell: Test; val: true
Sending a message:dev: testRule; cell: Test; val: true
dev: testRule; cell: Test; val: false
dev: testRule; cell: Test; val: true
Sending a message:dev: testRule; cell: Test; val: true
dev: testRule; cell: Test; val: false
dev: testRule; cell: Test; val: true
Sending a message:dev: testRule; cell: Test; val: true
dev: testRule; cell: Test; val: false
dev: testRule; cell: Test; val: true
Sending a message:dev: testRule; cell: Test; val: true

Если закомментировать строку dev["testRule/Message"] = ""; то все работает правильно, и правило "sendMessage" отрабатывает каждый раз. Но я хотел бы отчищать поле “testRule/Message” в web-интерфейсе после отправки сообщения.

Проблема в том, что вы отправляете в топик пустое значение, а whenChanged на пустое значение не реагирует (пустое значение используется в служебных целях). Если вы замените “” на " " (пробел), то все заработает так, как вы ожидаете.

Хорошо, но пустое значение отправляется сразу после публикации самого сообщения. Почему whenChanged не отрабатывает следующее непустое сообщение?

Я смотрю ваш код в первом сообщении. Уточните, про какие строки вы говорите, а то я сообразить не могу.

Смотрите, при переключении "testRule/Test" срабатывает правило "test", в котором публикуется новое сообщение в dev["testRule/Message"]. Т.к. switch при каждом переключении выдает то true, то false, сообщения все время разные.
Но. Если в правиле "sendMessage" есть строка dev["testRule/Message"] = "", то правило срабатывает через раз при переключении переключателя, если строку убрать, то правило отрабатывает каждый раз при переключении переключателя.
Почему так? Ведь при каждом переключении переключателя из правила "test" в dev["testRule/Message"] публикуется сообщение точно отличное от предыдущего.

Это тоже связано с внутренней кухней wb-rules. whenChanged не срабатывает на пустое значение, и на первое после пустого, если все это происходит после подписки на топик. Нужно все это для корректной обработки рестарта драйверов. Просто не используйте публикацию пустых значений.

Спасибо. Теперь понятно. Думаю стоит добавить информацию об этом в документацию к wb-rules. А то там сказано:

При задании whenChanged правило срабатывает при любых изменениях значений параметров, указанных в массиве.

И такое поведение кажется нелогичным

Думаю прямо сейчас об этом. Напишу, что надумаю.

1 лайк

Обсужу с коллегами.