Отработка правил завязанных на счетчики при перезагрузке

В wb-rules настроены правила (по примерам из wiki) завязанные на счетчики длинных/коротких нажатий mcm8.
При перезагрузке контроллера как я понимаю происходит инициализация wb-rules, который видит ?обновление? Значинения Счетчика и включает свет, столкнулся с проблемой, когда ночью пропадает электричество, а затем появляется - у меня включается добрая половина освещения дома.
Вопроса собственно два:

  1. Есть ли возможность сделать задержку отработки правил после старта системы/перезагрузки драйвера serial?
  2. если нет, как бороться с данной ситуацией?

На данный момент поборол таким костылём, но душой и головой понимаю что это как то не правильно, каждый раз добавлять обработку еще одного параметра при сработке правила…

Добрый день.
Вы можете скинуть свои скрипты? Лучше в архив запаковать, чтоб портал пустил.

Не могу никак добраться до пк чтоб скачать файлы, прикладываю текстом пример:

/* 1. Одиночное нажатие на включение*/
function button(name, input, output) {
  defineRule({
    whenChanged: input + " Single Press Counter",
      then: function (newValue, devName, cellName) {
        if (newValue!=null) {
          if (dev[output]= true && dev[output]) {
          dev[output] = false;
          }
          else {dev[output] = true;}
        }
  }
 })};
 
button("tualetvent", "wb-mcm8_138/Input 4", "wb-mr6cu_43/K5");
button("masterwent", "wb-mcm8_203/Input 4", "wb-mr6cu_26/K3");

Поможете?

2 сообщения были перенесены в новую тему: Открытие ворот при скачке напряжения

Эту тему я почитал, и другие тоже. НИГДЕ нет итогового ответа, обходные пути типа исключения NULL не работают, отсрочка работы правил от uptime - не решает проблему перезагрузки драйвера (что во время пусконаладки, как в моем случае длящейся уже второй месяц доставляет проблем, пару раз ребенка радбудил((

При пропадании питания счетчики нажатий внутри модулей сбрасываются на 0, но в mqtt топиках их значения остаются. После загрузки контроллера правило сравнивает значение в топике и в модуле, видит, что оно изменилось и срабатывает whenChanged правило, куда в качестве newValue приходит 0. Поэтому нужно делать общую проверку if (newValue > 0) {… код ващих правил …}

Кроме того у вас тут ошибка:

if (dev[output]= true && … ) - в этом месте вы присваиваете true устройству dev[output]. Для проверки нужно писать if (dev[output] == true && … ) .

Ну и этот код можно немного упросить.
Попробуйте вот так:

function button(name, input, output) {
  defineRule({
    whenChanged: input + " Single Press Counter",
      then: function (newValue, devName, cellName) {
        if (newValue > 0) {
          dev[output] = !dev[output];
        }
  }
 })};

В этом коде при изменении счетчика идет замена состояния dev[output] на противоположное, если счетчик изменился и не нулевой

1 лайк

Добавлю немного от себя. Код
var perem = parseInt(newValue) || 0;
Занесет в perem значение newValue или 0, если в newValue не число (true, NaN и так далее). А уже потом можно с переменной делать что угодно.

Спасибо, вечером попробую реализовать

В данном случае все равно нужно будет делать проверку.

if (perem > 0) {
...

Но js и так будет приводить newValue к числу при сравнении c другим числом внутри if()
т.е. он автоматом вызовет эту конвертацию.
Если там будет не число, то получится NaN, а любое сравнение с NaN всегда дает false.

if ("test string" > 0)  //false
if (true > 0)  //false
if (NaN > 0) //false
if (0 > 0) //false
if (14 > 0) //true

Таким образом можно всегда писать if (newValue > 0) - это покроет все случаи

Да, конечно можно и так писать. Но можно, например, сделать так
var perem = parseInt(newValue) || -1;
и потом

if (perem == -1) { // ага, какая фигня происходит, надо перебздеть }
if (perem == 0) { // модуль только что включился. }
if (perem > 0) {// накликали при живом модуле }

Но вообще в чатике уже проговорили :slight_smile:

Не сработало, на видео показал как отрабатывает

Тогда попробуйте такой вариант:

function button(name, input, output) {
 var input_topic = input + " Single Press Counter";
  var counter = dev[input_topic];
  defineRule({
    whenChanged: input_topic,
      then: function (newValue, devName, cellName) {
        if (newValue > 0 && counter != newValue) {
          counter = newValue;
          dev[output] = !dev[output];
        }
  }
 })};

Некорректно.

if (newValue != null && counter != newValue) {

Вернее. Так как счетчик (newValue) после переполнения, он 16-разрядный будет как раз равен 0, и на этом значении не сработает.

В общем спасибо всем (в том числе чату телеграмм). Разобрались, ниже приведу пример своего правила (вдруг кому понадобиться в схожей ситуации):

/* 1. Одиночное нажатие на включение*/ 
function button(name, input, output){ 
  var counter = dev[input + " Single Press Counter"]; 
  defineRule({
      whenChanged: input + " Single Press Counter",
      then: function(newValue, devName, cellName) {
        if (newValue > 0 && newValue != counter) {
            counter = newValue;
            dev[output] = !dev[output];
        }
      }
  });
};

button("tualetvent", "wb-mcm8_138/Input 4", "wb-mr6cu_43/K5");
button("masterwent", "wb-mcm8_203/Input 4", "wb-mr6cu_26/K3");

Да, но как писал выше один раз при переполнении счетчика в каждом цикле - не сработает.

Поторопился, при рестарте драйвера serial - вопросов нет, все работает как надо.
При рестарте WB - свет зажигается(

Итак, какие состояния у переменный в реализации? Чем они отличаются от ожидаемых?
Я навскидку вижу в

Выше писал почему нельзя сравнивать newValue с нулем.

инициализацию переменной неопределенным значением. Точнее - какое значение будет у (возможно еще несуществующего) на момент выполнения button топика? Высоковероятно что тот же null.
А вот если

var counter =0;

То при двух вероятных сценариях

  • перезапуск wb-rules (whenChanged не срабатывает)
  • перезапуск wb-mqtt-serial (срабатывает, но newValue возвращается то же значение что в counter)

сработает нештатно только при перезапуске самого диммера.

Увы, такое условие не отсекает скидывание счетчика в 0 при пропадании питания модуля.

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

function button(name, input, output) {
  defineRule({
    whenChanged: input + " Single Press Counter",
      then: function (newValue, devName, cellName) {
          dev[output] = !dev[output];}
)};

Это все.

В текущем варианте на уровень пользователя ложится довольно низкоуровневые особенности реализации.
А именно, он должен знать и учитывать:

  • при перезагрузке mqtt-драйвера топик со счетчиком переходит в COUNT->null → COUNT, что обрабатывается правилом whenChanged, куда приходит newValue=COUNT. Это нужно отсекать вручную. А это оказалось не так просто. так как при старте может еще не быть устройства из которого можно достать текущий счетчик. Это тоже нужно знать
  • при потере питания модуля, счетчик сбрасывается на 0. А правилах снова срабатывает whenChanged с newValue=0. Это снова нужно отсекать.

Я постарался написать код, который учтет все эти моменты, но выглядит это как адские костыли.

function buttonSinglePress(name, input, output) {
 var topic = input + " Single Press Counter";
 var counter = dev[topic];
 defineRule({
     whenChanged: topic,
     then: function(newValue, devName, cellName) {
       if (newValue > 0 && counter !== null && newValue != counter) {
         dev[output] = !dev[output];
       }
       counter = newValue;
     }
 });
}

У меня есть сильное ощущение, что оба эти момента можно учесть на уровне движка правил.

  • при перезагрузке драйвера не нотифицировать COUNT->null → COUNT, если значение не изменилось
  • при сбросе счетчика в 0 (при потере питания модуля) записывать это значение “втихую” в топик, и не вызывать whenChanged. Наверное тут можно ориентироваться на uptime модуля.

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

3 лайка