Теряется событие нажатия на кнопку на модуле ввода WBIO-DI-WB-14

Кейс - часто нажимаю на две кнопки одновременно
Ожидаю, что выходы реле 1 и 2 будут в одинаковом состоянии
На практике, через некоторое количество нажатия получаю рассинхрон: 1 - включен, 2 - выключен

Для того чтобы исключить физическое залипание самой кнопки, кнопки дополнительно подключены к 5 и 6 входам реле, которые переключают выходы 5 и 6 минуя контроллер.

Так как выходы 5 и 6 включены, делаю вывод, что обе кнопки были прожаты одинаковое количество раз, то есть проблема на стороне контролера.

Видео эксперимента

Переключение каналов 1 и 2 реализовано, через wb-rules 10 инпут управляет реле 1, а 9 - 2, подробности в коде (это кстати единственное правило на контролер, поэтому конфликтов быть не должно)
Смотри motion.js ниже (с удовольстивем прикрепил бы файлом, но нельзя)

В скрипте есть логи, из которых становится понятно, что последнее нажатие не детектируется нажатие на EXT1_IN10, в логах видно, что сработал только EXT1_IN9 (первые 3 строки).
См logs.txt ниже (В логи добавил свои комментарии)

Дальнейшее исследование:

  1. Попробовал повесить входы 10 и 9 на одну кнопку (поставил перемычку 10 и 9). Далее часто жму на кнопку 2. Нет никаких расхождений - все работает идеально - реле 1, 2, 5, 6 - все либо включены либо выключены одновременно.

  2. Попробовал убрать управление реле 1 и 2, но оставил контроль на реле 5 и 6. Вместо управления выходами реле, стал просто менять состояние переменных в памяти. В результате в памяти состояния переменных расходятся. В конце кейса button1.isOn != button2.isOn при этом светодиоды 5 и 6 горят
    Скрипт есть, но платформа не разрешает приложить больше 2 ссылок

Схема

Система
Batch No 7.3.4L/9 1D/G-1GC
DTS Version 733
HW Revision 7.3.4
Manufacturing Date 2023-08-30 12:45:56
Release name wb-2307
Release suite stable
Temperature Grade industrial

Можно приложить только 2 ссылки, поэтому придется оформлять как-то

motion.js

//Реагирует на 2 инпута от кнопок, включает/выключает 1 и 2 выходы реле подключеного по модбасу
//Отсылает 2 пакет по модбасу в одном одном обработчике (надеюсь что контроллер их сможет объеденить в один пакет, но это не точно)
//Логика объядинения пакетов была написана в попытке борьбы с рассинхроном
function MyTestModbus2()
{
    var button1 = {};
    button1.isOn = false;
    button1.doSwitch = function()
    {
      log("doSwitch 1, rnd: ", Math.random()); 
      dev["wb-mr6c_44/K1"] = button1.isOn;
    };

    var button2 = {};
    button2.isOn = false;
    button2.doSwitch = function()
    {
      log("doSwitch 2, rnd: ", Math.random()); 
        dev["wb-mr6c_44/K2"] = button2.isOn;
    };

    var callback = 0;
    var doSwitchBoth = function() 
    {
      log("doSwitchBoth, rnd: ", Math.random()); 
       dev["wb-mr6c_44/K1"] = button1.isOn;
       dev["wb-mr6c_44/K2"] = button2.isOn;
    }
  
    var action = function(my)
    {
      return function(newValue, devName, cellName)
      {
        log("devName:{}, cellName:{}, newValue:{}, rnd: ", devName, cellName, newValue, Math.random()); 
        if (newValue)
        {
          if (newValue)
          {
            //Когда кнопку отпустят, применется новое состояние
            my.isOn = !my.isOn;
            //тут самое интересное
            //callback - это то что сделает кнопка при отпускании
            // - если callback не установлен, значит другая кнопка не нажата, 
            //    поэтому планируем изиенить только свое состояние
            // - но если callback уже установлен, значит другая кнопка уже нажата, но не отжата (тк callback при отжатии сбрасывается)
            //   поэтому в качестве callback указывается doSwitchBoth
            //   первая отжатая кнопка выполнит callback и сбросит его
            //   вторая отжатая кнопка увидит callback == 0 и ничего не будет делать
            callback = callback ? doSwitchBoth : my.doSwitch;
          }
          return;
        }

        var fn = callback;
        callback = 0;
        if (fn)
        {
          fn();
        }
      }
    }
  
    defineRule({
      whenChanged: "wb-gpio/EXT1_IN9",
      then: action(button1)
    });

    defineRule({
      whenChanged: "wb-gpio/EXT1_IN10",
      then: action(button2)
    });

}


MyTestModbus2();

logs.txt


//-----КОНЕЦ------

//Конец 3 цикла нажатия
06-10-2023 11:53:37.151	INFO: [rule info] doSwitch 1, rnd:  0.5374596404490535
//-- Зарегистрировано нажатие/отжатие на кнопку 2 (EXT1_IN9) callback = button1.doSwitch 
06-10-2023 11:53:37.150	INFO: [rule info] devName:wb-gpio, cellName:EXT1_IN9, newValue:false, rnd:  0.498003186977639
//-- ПРОБЛЕМА ТУТ: не заренистрировано нажатие на кнопку 1 (EXT1_IN10)
//-- ожидаю тут ивент "devName:wb-gpio, cellName:EXT1_IN9, newValue:true", но его нет
06-10-2023 11:53:36.692	INFO: [rule info] devName:wb-gpio, cellName:EXT1_IN9, newValue:true, rnd:  0.28606293889131895

//Конец 2 цикла нажатия
//-- Отжата кнопка 1 (EXT1_IN10), callback == 0 - ничего не делаем
06-10-2023 11:53:36.014	INFO: [rule info] devName:wb-gpio, cellName:EXT1_IN10, newValue:false, rnd:  0.13134387116051938
06-10-2023 11:53:36.012	INFO: [rule info] doSwitchBoth, rnd:  0.18822204755706717
//-- Отжата кнопка 2 (EXT1_IN9), выполнен callback == doSwitchBoth (строчка выше)
06-10-2023 11:53:36.009	INFO: [rule info] devName:wb-gpio, cellName:EXT1_IN9, newValue:false, rnd:  0.8231331161462524
//--- Нажата кнопка 1 (EXT1_IN10) callback = doSwitchBoth
06-10-2023 11:53:35.496	INFO: [rule info] devName:wb-gpio, cellName:EXT1_IN10, newValue:true, rnd:  0.24481479672704098
//--- Нажата кнопка 2 (EXT1_IN9) callback = button1.doSwitch 
06-10-2023 11:53:35.491	INFO: [rule info] devName:wb-gpio, cellName:EXT1_IN9, newValue:true, rnd:  0.13787682651964672


//--- Конец 1 цикла нажатия
//-- Отжата кнопка 1 (EXT1_IN10), callback == 0 - ничего не делаем
06-10-2023 11:53:34.769	INFO: [rule info] devName:wb-gpio, cellName:EXT1_IN10, newValue:false, rnd:  0.4059453534465999
06-10-2023 11:53:34.762	INFO: [rule info] doSwitchBoth, rnd:  0.9313848723365667
//-- Отжата кнопка 2 (EXT1_IN9), выполнен callback == doSwitchBoth (строчка выше)
06-10-2023 11:53:34.761	INFO: [rule info] devName:wb-gpio, cellName:EXT1_IN9, newValue:false, rnd:  0.10404331039606052
//--- Нажата кнопка 1 (EXT1_IN10) callback = doSwitchBoth
06-10-2023 11:53:34.631	INFO: [rule info] devName:wb-gpio, cellName:EXT1_IN10, newValue:true, rnd:  0.5071934871149298
//--- Нажата кнопка 2 (EXT1_IN9) callback = button1.doSwitch 
06-10-2023 11:53:34.123	INFO: [rule info] devName:wb-gpio, cellName:EXT1_IN9, newValue:true, rnd:  0.7528331248253234

//-----НАЧАЛО------
06-10-2023 11:53:22.329	INFO: reloading file: /etc/wb-rules/motion.js

Прикладываю диагностику

приложен диагностический архив, доступен только сотрудникам поддержки
(218.2 KB)

Добрый день.
Какая длительность замыыкания входов модуля WD-14?
По документации:

Здравствуйте, по логам видно, что более 500мс. Так же можно ознакомится с видео в тиките (логи и видео синхронизированы, те снимались в одно время).

У меня не удается воспроизвести подобное поведение. Я соединил ва входа WBIO-DI-WD-14 и замыкаю их раз в 200мс на 50 мс.
Изменения состояния фиксирую просто

//10_09_test_01.js
var in1 = "wb-gpio/EXT3_IN4"
var in2 = "wb-gpio/EXT3_IN5"
var in1counter =0,in2counter = 0

log.info("Start", in1counter, in1counter)

function makeRuleIn (inName, nameCounter){
  nameCounter=eval(nameCounter)
  //log.info("test", inName, nameCounter)
  defineRule("counter_"+inName, {
    whenChanged: inName,
    then: function(value) {
      nameCounter++
      log.info("inc", inName, nameCounter)
    }
  }
  )
}

makeRuleIn(in1, "in1counter");
makeRuleIn(in2, "in2counter");

получая по инеременту каждое изменение состояния.

я попробую запустить ваш скрипт на своем стенде и отпишусь о результате.
Но перед этим мне нужно знать, используете ли вы два разных выключателя или один соеденный с двумя входами EXT3_IN4 и EXT3_IN5 ?
Это важно потому, что во втором случае у меня тоже все отлично работает (см тикет “Дальнейшее исследование” пункт 1)

Один, я фактически использую канал реле на соседнем модуле чтобы замыкать два объединенные входа на iGnd моделя.
Как я понял - основная наблюдаемая проблема в том что не срабатывает один из входов при их синхронном замыкании.

Я постарался очень подробно описать проблему, что бы вам было легче ее воспроизвести, прочтите, пожалуйста, тикет внимательно, там вся информация полезна.
Лично мое мнение, что при близком срабатывание выключателям происходи проблема. Если они срабатывают одновременно или с достояний разницей во времени - все работает отлично.
В вашем случае нужно инкрементировать счётчик под условием (value == false) и вместо общей кнопки использовать 2 разные, и стараться жать (точне отжимать их одновременно)

Для чего? Ну, можно, конечно считать только фронты или только срезы.

Да, могу взять два канала реле, попробую. Нажимать кнопки руками - это крайне непродуктивно, думаю. Очень легко недожать или пропустить… У меня цель - воспроизвести поведение так, чтобы, оно воспроизводилось устойчиво.

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

Получилось воспроизвести и при помощи реле, воспроизводится через раз, но стабильно
wb-rules_20231010T021603.log (13.8 KB)
(некоторые строки в логе продублированы, этот похоже баг в веб интерфейсе выгрузки логов)

Скрипт для воспроизведения (нужно позапускать несколько раз)

var in1 = "wb-gpio/EXT1_IN9"
var in2 = "wb-gpio/EXT1_IN10"
var out1 = "wb-mr6c_44/K1";
var out2 = "wb-mr6c_44/K2";

//out1 соединен на in1, out2 соединен на in2
//правило makeRuleIn инкрементирует счетчик in1counter и in2counter 
//при размыкании in1 или in2
//В результате можем получить разное значение in1counter и in2counter
var in1counter =0,in2counter = 0

log("Start", in1counter, in1counter)

function makeRuleIn (inName, nameCounter){
  nameCounter=eval(nameCounter)
  //log("test", inName, nameCounter)
  defineRule("counter_"+inName, {
    whenChanged: inName,
    then: function(newValue, devName, cellName) {
      if(!newValue)
      {
        nameCounter++
        log("inc", inName, nameCounter)
      }
    }
  }
  )
}

makeRuleIn(in1, "in1counter");
makeRuleIn(in2, "in2counter");

var needInit = true;
defineRule({
  when: function() {
    if (needInit)
    {
      needInit = false;
      return true;
    }
    return false;
  },
  then: function (newValue, devName, cellName) {
    log("Init");
    dev[out1] = false;
    dev[out2] = false;

    var sq = 0;
    var action = function(on1, on2, off1, off2) {
      setTimeout(function() {
        log("On 1 sq: {}", ++sq);
        dev[out1] = true;
      }, on1);
      
      setTimeout(function() {
        log("On 2 sq: {}", ++sq);
        dev[out2] = true;
      }, on2);
      
      setTimeout(function() {
        log("Off 1 sq: {}", ++sq);
        dev[out1] = false;
      }, off1);
      
      setTimeout(function() {
        log("Off 2 sq: {}", ++sq);
        dev[out2] = false;
      }, off2);
    };
    for (var i=0; i<10;i++)
    {
      setTimeout(function() {
        setTimeout(function() {
          action(123, 631, 761, 769);
        }, 0);
    
        
        setTimeout(function() {
          action(491, 496, 1009, 1014);
        }, 1000);
    
        setTimeout(function() {
          action(692, 670, 1150, 1151);
        }, 2000);
      }, 1000 + 3500* i);
    }

  }
});

Да, воспроизвел.

//10_09_test_01.js
var in1 = "wb-gpio/EXT3_IN9"
var in2 = "wb-gpio/EXT3_IN10"
var in1counter =0, in2counter = 0, out1counter =0, out2counter = 0

var out1 = "wb-gpio/EXT2_K15";
var out2 = "wb-gpio/EXT2_K16";

//out1 соединен на in1, out2 соединен на in2
//правило makeRuleIn инкрементирует счетчик in1counter и in2counter 
//при размыкании in1 или in2
//В результате можем получить разное значение in1counter и in2counter

log("Start", in1counter, in1counter)

function makeRuleIn (inName, nameCounter){
  nameCounter=eval(nameCounter)
  var oldDate = new Date();
  defineRule("counter_"+inName, {
    whenChanged: inName,
    then: function(newValue, devName, cellName) {
      if(!newValue)
      {
        tDate = new Date();
        nameCounter++
        //log("inc", inName, nameCounter, tDate-oldDate) //Вывод времени после предыдущего срабатывания
        log("inc", inName, nameCounter)
        oldDate = tDate;
      }
    }
  }
  )
}
 
makeRuleIn(in1, "in1counter");
makeRuleIn(in2, "in2counter");

makeRuleIn(out1, "out1counter");
makeRuleIn(out2, "out2counter");


function slowPWM_generator(namePWM, devicePWM, period, periodOn){
  
  //Создаем таймер для канала.
  this[namePWM+"_IntervalID"] = setInterval(function () {
  	//Тут Включим канал, если значение контрола виртуального устройства не 0
      dev[devicePWM]=true;
      //и сразу зададим время "включенного" состояние
      setTimeout(function () {
        //По таймауту - отключаем устройство
        dev[devicePWM]=false;
      }, periodOn);
  }, period); 
}


//топик физического устройства
//период
//время включения в миллисекундах
slowPWM_generator("Device1", out1, 400, 70)
slowPWM_generator("Device2", out2, 410, 70)

Счетчики расходятся если время срабатывания (размыкания) каналов близко. Если включить вывод времени после предыдущего срабатывания - виден момент пропуска.

Oct 10 11:10:01 wirenboard-AWI3MCGC wb-rules[15024]: INFO: [rule info] inc wb-gpio/EXT3_IN10 617
Oct 10 11:10:01 wirenboard-AWI3MCGC wb-rules[15024]: INFO: [rule info] inc wb-gpio/EXT2_K15 641
Oct 10 11:10:01 wirenboard-AWI3MCGC wb-rules[15024]: INFO: [rule info] inc wb-gpio/EXT3_IN9 633
Oct 10 11:10:01 wirenboard-AWI3MCGC wb-rules[15024]: INFO: [rule info] inc wb-gpio/EXT2_K16 626
Oct 10 11:10:02 wirenboard-AWI3MCGC wb-rules[15024]: INFO: [rule info] inc wb-gpio/EXT3_IN10 618
Oct 10 11:10:02 wirenboard-AWI3MCGC wb-rules[15024]: INFO: [rule info] inc wb-gpio/EXT2_K15 642
Oct 10 11:10:02 wirenboard-AWI3MCGC wb-rules[15024]: INFO: [rule info] inc wb-gpio/EXT3_IN9 634
Oct 10 11:10:02 wirenboard-AWI3MCGC wb-rules[15024]: INFO: [rule info] inc wb-gpio/EXT2_K16 627
Oct 10 11:10:02 wirenboard-AWI3MCGC wb-rules[15024]: INFO: [rule info] inc wb-gpio/EXT3_IN10 619
Oct 10 11:10:02 wirenboard-AWI3MCGC wb-rules[15024]: INFO: [rule info] inc wb-gpio/EXT2_K15 643
Oct 10 11:10:02 wirenboard-AWI3MCGC wb-rules[15024]: INFO: [rule info] inc wb-gpio/EXT3_IN9 635
Oct 10 11:10:02 wirenboard-AWI3MCGC wb-rules[15024]: INFO: [rule info] inc wb-gpio/EXT2_K16 628
Oct 10 11:10:02 wirenboard-AWI3MCGC wb-rules[15024]: INFO: [rule info] inc wb-gpio/EXT3_IN10 620
Oct 10 11:10:02 wirenboard-AWI3MCGC wb-rules[15024]: INFO: [rule info] inc wb-gpio/EXT2_K15 644
Oct 10 11:10:02 wirenboard-AWI3MCGC wb-rules[15024]: INFO: [rule info] inc wb-gpio/EXT3_IN9 636
Oct 10 11:10:03 wirenboard-AWI3MCGC wb-rules[15024]: INFO: [rule info] inc wb-gpio/EXT2_K16 629
Oct 10 11:10:03 wirenboard-AWI3MCGC wb-rules[15024]: INFO: [rule info] inc wb-gpio/EXT3_IN10 621
Oct 10 11:10:03 wirenboard-AWI3MCGC wb-rules[15024]: INFO: [rule info] inc wb-gpio/EXT2_K15 645
Oct 10 11:10:03 wirenboard-AWI3MCGC wb-rules[15024]: INFO: [rule info] inc wb-gpio/EXT3_IN9 637
Oct 10 11:10:03 wirenboard-AWI3MCGC wb-rules[15024]: INFO: [rule info] inc wb-gpio/EXT2_K16 630
Oct 10 11:10:03 wirenboard-AWI3MCGC wb-rules[15024]: INFO: [rule info] inc wb-gpio/EXT3_IN10 622
Oct 10 11:10:03 wirenboard-AWI3MCGC wb-rules[15024]: INFO: [rule info] inc wb-gpio/EXT2_K15 646
Oct 10 11:10:03 wirenboard-AWI3MCGC wb-rules[15024]: INFO: [rule info] inc wb-gpio/EXT3_IN9 638
Oct 10 11:10:04 wirenboard-AWI3MCGC wb-rules[15024]: INFO: [rule info] inc wb-gpio/EXT2_K16 631
Oct 10 11:10:04 wirenboard-AWI3MCGC wb-rules[15024]: INFO: [rule info] inc wb-gpio/EXT3_IN10 623
Oct 10 11:10:04 wirenboard-AWI3MCGC wb-rules[15024]: INFO: [rule info] inc wb-gpio/EXT2_K15 647

Призову настоящих программистов.