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

1 сообщение было перенесено в новую тему: Запись в EEPROM счетчиков нажатия

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

Идея интересная, но дело в том, что при подписке непосредственно на Input N могут случаться пропуски нажатий, если действие не попало в окошко запроса Modbus (это зависит от скорости и загруженности шины).
Как раз из-за этих пропусков и были введены счетчики. Они гарантированно отслеживаются, так как можно сравнить предыдущее и следующее значение.

Используя Input N как триггер на открытие “временного коридора” в 1200мс другие правила на счетчики так же будут получать пропуски нажатий.

Тогда получается единственное решение - ждать от производителя решения данной баги на уровне драйвера. Ведь даже если считать, что все устройства работают от ИБП и не бывает проблем с их физическим отвалом, то как быть при перезагрузке WB, или если завис какой-то из сервисов и произошла перезагрузка отдельного сервиса - везде всё будет моргать или включаться?) Да наверное в идиале перезагрузок быть не должно, а вот как на практике?

А есть ли в ПО какой-то доступный пользователю скрипта индикатор, что модуль отвалился или что сервис перезапустился? (Перезагрузку сервиса самих правил наверное легко отследить с помощью инициализированной переменной, или просто в фрагменте кода за пределами определения функций сделать секцию инициализации.)

И так, послу бурного обсуждения в чате постараюсь написать все заново и более конкретно:
Кратко предыстория, живу в стройке, ПНР системы провожу после работы по вечерам и ночам. В поселке тоже стройка - часто отключают электричество. Я изучил вдоль и поперек всю документацию по wb-rules и кучу веток форума.
На данный момент, в конкретно рассматриваемой ситуации используем Контроллер+MCM8+любое реле.
Изначально мной было взято типовое правило из Wiki по обработке счетчиков нажатий.
В процессе проживания обнаружил, что после отключения электроэнергии и последующим ее включением - ВСЕ правила, в которых код формата -

whenChanged: "wb-mcm8_20/Input 1 Single Press Counter"

реагируют, то есть у меня включается ВЕСЬ свет дома.
Затем обнаружил, что аналогичная ситуация происходит, когда я меняю какие либо параметры любых устройств в драйвере serial (после нажатия кнопки сохранить - происходить перегрузка драйвера с очисткой и последующим наполнением топиков устройств)
Аналогичная ситуация произошла когда я выключал/включал V-out на контроллере.
После недолгих поисков я понял в чем загвоздка: происходит очистка в null топика, а затем его наполнение (Например, в счетчике было значение 10, я перезагрузил контроллер - в топик прилетело значение null - под этим я подразумеваю полностью пустое значение в топике, потом (после загрузки) подгрузилось обратно значение 10, соответсвенно WhenChanged обработал изменение топика)
Я сделал попытку внедрить в код несколько проверок, но результата не получил. На данный момент у меня в работе используется следующий код:

Спойлер
function buttonSinglePress(name, input, output) {
  
  
  var topic = input + " Single Press Counter";
  var counter = dev[topic];
  defineRule({
      whenChanged: topic,
      then: function(newValue, devName, cellName) {
        log.debug("button:{} device:{}, cel:{} val={} counter={}", name, devName, cellName, newValue, counter);
        if (newValue > 0 && counter !== null && newValue != counter) {
          log.debug("Реле переключено {}", output);
          dev[output] = !dev[output];
        }
        counter = newValue;
      }
  });
}

buttonSinglePress("tualetvent", "wb-mcm8_138/Input 4", "wb-mr6cu_43/K5");
buttonSinglePress("masterwent", "wb-mcm8_203/Input 4", "wb-mr6cu_26/K3");
buttonSinglePress("garderob", "wb-mcm8_211/Input 4", "wb-mr6cu_44/K6");
buttonSinglePress("spalnya", "wb-mcm8_211/Input 5", "wb-mr6cu_44/K3");
buttonSinglePress("zal1", "wb-mcm8_211/Input 7", "wb-mr6cu_58/K4");  
buttonSinglePress("zal2", "wb-mcm8_211/Input 8", "wb-mr6cu_58/K5");
buttonSinglePress("divan2", "wb-mcm8_211/Input 2", "wb-mr6cu_58/K5");
buttonSinglePress("vhod1", "wb-mcm8_138/Input 1", "wb-mr6cu_54/K2");
buttonSinglePress("vhod2", "wb-mcm8_138/Input 2", "wb-mr6cu_54/K3");
buttonSinglePress("kuhnya-stena", "wb-mcm8_138/Input 5", "wb-mr6cu_54/K5");
buttonSinglePress("kuhnya2", "wb-mcm8_138/Input 6", "wb-mr6cu_54/K4");
buttonSinglePress("bra1", "wb-mcm8_203/Input 1", "wb-mr6cu_53/K5");
buttonSinglePress("bra2", "wb-mcm8_203/Input 7", "wb-mr6cu_53/K2");
buttonSinglePress("detskay", "wb-mcm8_138/Input 7", "wb-mr6cu_58/K3");
buttonSinglePress("detskay", "wb-mcm8_138/Input 8", "wb-mr6cu_58/K2");

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

Так не хотите попробовать? Чтобы в правила не летел всякий непредсказуемый мусор, пока вся система не загрузится

Данное решение исправляет ситуацию с перезагрузкой - но когда происходит перезапуск serial, или пропадает питания конкретно модуля MCM8 - нет

Изначально же и была озвучена проблема, что у вас при повторном включении электричества включается весь свет.
Перезапуск Serial уже контролируемый процесс ПНР

Я вроде в 26 сообщении указал не только перезагрузку

Это я видел, но мне показалось справедливым отделить ПНР от перезагрузки по независящим причинам - из сообщения №1
Я тоже обращал внимание, что мне в Телегу летят уведомления о протечках с WB-MWAC при перезагрузке Serial.
Но это не сильно парит, так как контролируемый процесс.

По справедливости я бы тоже внес предложение в библиотеке WhenChanged внести исключение в обработку поступления значения null

хотя это очередной костыль, но можно попробовать анализировать регистр
104­-105 0x0068 - 0x0069 Input RO u32 Время работы с момента загрузки секунды
игнорируя первые 2-5 секунд.

Добрый день! В понедельник коллеги смогут заняться подробнее, пока пара замечаний.

  1. Кажется, вызов правила по whenChanged со значением newValue==null - это баг. Это значение отправляется сервисом wb-mqtt-serial при завершении и должно вызывать удаление устройства, а не вызов правила. Проверим, исправим.

  2. Обработку переполнения и всего остального можно сделать, сохраняя предыдущее состояние. Например, так:

defineRule({
  whenChanged: "myvdev/counter1",
  then: function (newValue, devName, cellName) {
    log("срабатывание правила newValue: {}, was: {}".format(newValue, this.prevValue));

    // игнорируем сообщение при выгрузке wb-mqtt-serial: 123 => null
    if (newValue === null) return; 
    
    // загрузка wb-mqtt-serial восстановление предыдущего значения, null => 123. Игнорируем, только если значение не изменилось. Если изменилось - было нажатие перед загрузкой драйвера.
    if (newValue == this.prevValue) return;

    // ноль мог прийти после перезагрузки modbus-устройства по питанию, а мог из-за переполнения
    // ожидаем переполнения, только если счётчик был близок к пределу 16 бит
    if (newValue == 0) {
      if (this.prevValue < (65536 - 5)) {
        return;
      }
    }

    log("тут обработка нажатия!");
    
    this.prevValue = newValue; // эта строчка должна быть в конце
  }
});




Важно №1: у меня не получилось воспроизвести неправильную срабатывания правила с null.

Важно №2: пожалуйста, приложите диагностический архив, как мы вас просили.

1 лайк

Добрый день! Прикладываю диагностический архив.
Мне кажется проблема не в newValue==null (которую легко побороть одной проверкой на null) а именно в последующем значении параметра, то есть было null - стало не null.

Сегодня ночью проснулся о. того что во всей квартире опять горел свет -_-

На счет:

Важно №1 : у меня не получилось воспроизвести неправильную срабатывания правила с null.

У вас не отрабатывает мое правило при перегрузке контроллера/изменении параметров serial?

Добрый день.
Мы пока глобально разбираемся в проблеме.
Как временное решение, было предложено исключить все условия ложного срабатывания правила.
Вы пробовали применить этот скрипт у себя?
Если что, поправил под вашу задачу и чуть-чуть доработал:

/* 1. Одиночное нажатие на включение*/
function button(name, input, output) {
  defineRule({
    whenChanged: input + " Single Press Counter",
    then: function (newValue, devName, cellName) {
      log("срабатывание правила newValue: {}, output: {}, this.prevValue: {}".format(newValue, output, this.prevValue));

      if (newValue === null || newValue == this.prevValue) return;
      if (newValue == 0 && this.prevValue < (65536 - 5)) return;
      if (newValue == 0 && !this.prevValue) return;

      dev[output] = !dev[output];
      this.prevValue = newValue;
    }
  });
}

У меня прошли следующие тесты:

  1. Перезапуск wb-mqtt-serial
    (Поведение: состояние выходов сохраняется)
  2. Перезагрузка контроллера
    (Поведение: состояние выходов сохраняется)
  3. Перезапуск wb-rules
    (Поведение: состояние выходов сохраняется)
  4. Отключение питания модулей (V_Out On → Off → On)
    (Поведение: состояние выходов не сохраняется, но и не переключается, все выходы в выключенном состоянии)

P.S. null я тоже не смог отловить.

Круто! Наличие this.prevValue позволяет элегантно решить вопрос! Не нашел этого в документации. Это незадокументированная фича? Какое у него значение? Предыдущее значение топика?

prevValue реально звучит как то что искал пару месяцев, спрашивал в чате несколько раз. Очень жаль что про данный параметр не прописано в wiki и на gite, это бы решало много проблем, завтра накачу на контроллере Ваше правило и постараюсь протестировать, дам обратную связь

1 лайк

Это просто определение переменной в контексте. this: контекст выполнения функций — JavaScript — Дока

А, т.е. это то же что предлагалось через

function buttonSinglePress(name, input, output) {
 var counter = dev[topic];
....

только не через замыкание, а через this.prevValue.

Тогда проблема остается, в случае с перезагрузкой драйвера, если prevValue ни разу не сохранялся (например, перегрузить контроллер и потом драйвер, либо перезагрузить wb-rules - потом драйвер).

При перезапуске драйвера в whenChanged приходит newValue: 10, this.prevValue: undefined.

В итоге мы получаем переключение.

Тестовый код
function button(name, input, output) {
  log("--- Определение правила button [{}] input: {}, output: {}",name, input, output);
  defineRule({
    whenChanged: input + " Single Press Counter",
    then: function (newValue, devName, cellName) {
      log(">>> Cрабатывание правила button [{}] input: {}/{}, newValue: {}, output: {}, this.prevValue: {}",name, devName, cellName, newValue, output, this.prevValue);

      if (newValue === null || newValue == this.prevValue) return;
      if (newValue == 0 && this.prevValue < (65536 - 5)) return;
      if (newValue == 0 && !this.prevValue) return;

      log("!!! Переключаем состояние dev['{}']".format(output));
      //dev[output] = !dev[output];
      this.prevValue = newValue;
    }
  });
}

button("test button", "wb-mr6c_75/Input 1", "test_output" );
Лог после перезагрузки контроллера, потом драйвера
-- Boot 464238ed115e485b8057d5f7412868b1 --
Apr 10 10:38:03 wirenboard-AC6A3GB6 systemd[1]: Started MQTT Rule engine for Wiren Board.
Apr 10 10:38:03 wirenboard-AC6A3GB6 wb-rules[4294]: INFO: broker URL is default and mosquitto socket detected, trying to connect via it
Apr 10 10:38:03 wirenboard-AC6A3GB6 wb-rules[4294]: INFO: driver is created
Apr 10 10:38:03 wirenboard-AC6A3GB6 wb-rules[4294]: INFO: [wbgo_mqtt] rules-wirenboard-AC6A3GB6-4294: MQTT connection established
Apr 10 10:38:04 wirenboard-AC6A3GB6 wb-rules[4294]: INFO: driver loop is started
Apr 10 10:38:04 wirenboard-AC6A3GB6 wb-rules[4294]: INFO: wait for driver to become ready
Apr 10 10:38:08 wirenboard-AC6A3GB6 wb-rules[4294]: INFO: driver is ready
Apr 10 10:38:08 wirenboard-AC6A3GB6 wb-rules[4294]: INFO: [rule info] using file /var/lib/wirenboard/wbrules-persistent.db for persistent DB
Apr 10 10:38:08 wirenboard-AC6A3GB6 wb-rules[4294]: INFO: [wbgo_mqtt] wb-rules-engine-wirenboard-AC6A3GB6-4294: MQTT connection established
Apr 10 10:38:08 wirenboard-AC6A3GB6 wb-rules[4294]: INFO: [engine] Starting main loop
Apr 10 10:38:08 wirenboard-AC6A3GB6 wb-rules[4294]: INFO: the engine is ready
Apr 10 10:38:08 wirenboard-AC6A3GB6 wb-rules[4294]: INFO: [engine] Starting sync loop
Apr 10 10:38:10 wirenboard-AC6A3GB6 wb-rules[4294]: WARNING: [device] Unknown metadata for device metrics: 'error'
Apr 10 10:38:11 wirenboard-AC6A3GB6 wb-rules[4294]: WARNING: [rule warning] DAC: no config file
Apr 10 10:38:12 wirenboard-AC6A3GB6 wb-rules[4294]: INFO: [rule info] --- Определение правила button [test button] input: wb-mr6c_75/Input 1, output: test_output
Apr 10 10:38:12 wirenboard-AC6A3GB6 wb-rules[4294]: INFO: [rule info] _update_git_status started!
Apr 10 10:38:12 wirenboard-AC6A3GB6 wb-rules[4294]: INFO: [rule info] add your rules to /etc/wb-rules/
Apr 10 10:38:13 wirenboard-AC6A3GB6 wb-rules[4294]: INFO: all rule files are loaded
Apr 10 10:39:12 wirenboard-AC6A3GB6 wb-rules[4294]: INFO: [rule info] _update_git_status started!
Apr 10 10:40:11 wirenboard-AC6A3GB6 wb-rules[4294]: INFO: [rule info] _update_git_status started!
Apr 10 10:40:21 wirenboard-AC6A3GB6 wb-rules[4294]: INFO: [rule info] >>> Cрабатывание правила button [test button] input: wb-mr6c_75/Input 1 Single Press Counter, newValue: 10, output: test_output, this.prevValue: undefined
Apr 10 10:40:21 wirenboard-AC6A3GB6 wb-rules[4294]: INFO: [rule info] !!! Переключаем состояние dev['test_output']

Лог после перезагрузки правил, потом драйвера
Apr 10 10:45:10 wirenboard-AC6A3GB6 wb-rules[11664]: INFO: driver is created
Apr 10 10:45:10 wirenboard-AC6A3GB6 wb-rules[11664]: INFO: [wbgo_mqtt] rules-wirenboard-AC6A3GB6-11664: MQTT connection established
Apr 10 10:45:10 wirenboard-AC6A3GB6 wb-rules[11664]: INFO: driver loop is started
Apr 10 10:45:10 wirenboard-AC6A3GB6 wb-rules[11664]: INFO: wait for driver to become ready
Apr 10 10:45:11 wirenboard-AC6A3GB6 wb-rules[11664]: INFO: driver is ready
Apr 10 10:45:11 wirenboard-AC6A3GB6 wb-rules[11664]: INFO: [rule info] using file /var/lib/wirenboard/wbrules-persistent.db for persistent DB
Apr 10 10:45:11 wirenboard-AC6A3GB6 wb-rules[11664]: INFO: [wbgo_mqtt] wb-rules-engine-wirenboard-AC6A3GB6-11664: MQTT connection established
Apr 10 10:45:11 wirenboard-AC6A3GB6 wb-rules[11664]: INFO: [engine] Starting main loop
Apr 10 10:45:11 wirenboard-AC6A3GB6 wb-rules[11664]: INFO: [engine] Starting sync loop
Apr 10 10:45:11 wirenboard-AC6A3GB6 wb-rules[11664]: INFO: the engine is ready
Apr 10 10:45:12 wirenboard-AC6A3GB6 wb-rules[11664]: WARNING: [rule warning] DAC: no config file
Apr 10 10:45:12 wirenboard-AC6A3GB6 wb-rules[11664]: INFO: [rule info] --- Определение правила button [test button] input: wb-mr6c_75/Input 1, output: test_output
Apr 10 10:45:12 wirenboard-AC6A3GB6 wb-rules[11664]: INFO: [rule info] _update_git_status started!
Apr 10 10:45:12 wirenboard-AC6A3GB6 wb-rules[11664]: INFO: [rule info] add your rules to /etc/wb-rules/
Apr 10 10:45:12 wirenboard-AC6A3GB6 wb-rules[11664]: INFO: all rule files are loaded
Apr 10 10:45:38 wirenboard-AC6A3GB6 wb-rules[11664]: INFO: [rule info] >>> Cрабатывание правила button [test button] input: wb-mr6c_75/Input 1 Single Press Counter, newValue: 10, output: test_output, this.prevValue: undefined
Apr 10 10:45:38 wirenboard-AC6A3GB6 wb-rules[11664]: INFO: [rule info] !!! Переключаем состояние dev['test_output']

Да. Но зачем переменную определять до фактического выполнения? Неопределенная переменная - это маркер первого срабаттывания что тут и показано.

А как часто такое происходит и из-за чего может быть? То есть какой сценарий возникновения?