Триггерить правило по паттерну mqtt?

Привет, начинаю помалу закапываться в скрипты.

Задача на разминку - стучать в скаду, если отвалился какой-либо датчик - насовсем отвалился (некоторые “хлопают” раз в 5-100 минут, это нужно игнорировать).
Соотв надо отслеживать “/devices/+/controls/+/meta/error” и ставить таймер при появлении ашыпки на дивайсе, гасить его при пропадении, а при непропадении громко кричать.

Как изящнее прибить отслеживание топика meta/error к правилам?

Спасибо.

Вот тут расписано:

Ну и чтобы убрать “дребезг”, то есть помехи:
https://support.wirenboard.com/t/debounce-antidrebezg/6784
Идея в том - что при срабатывании правила (появлении meta error) запускается таймер и если значение на момент завершения таймера ни разу не поменялось (остался error) - тогда уже точно срабатывание не единичное.

Это я видел. А если у меня 240 устройств? Спрашиваю именно про вайлдкард.

404, увы. Но сам таймер поднять не проблема, я думаю.

Спасибо.

Апд. Сработало trackMqtt(), думаю, пристегнем.

Вот только хотел про него написать. Имя топика тоже возвращается, можно парсить и отдавать.

//01_08_test_1.js

//Идея в том, чтобы определить переключение только после того как знчение в течении заданного
// времени находится БОЛЬШЕ уставки.

var devInput = "01_08_Test0/test0"; // устройство-источник значений.
var compValue = 10; //Значение, превышение которого отслеживаем
var debounceTime = 2000; //Время "дребезга" в миллисекундах

var timerId = null; //тут будем сохранять идентификатор таймера

log.info("start")

defineRule( "debounceTime" ,{
  whenChanged: "01_08_Test0/test0",
  then: function (newValue, devName, cellName){
    log.info("I’m here!", newValue)
    if(newValue > compValue) { //Если значение БОЛЬШЕ
      log.info("Compare BIGGER", newValue)
      if (timerId){ //Если таймер УЖЕ есть
        log.info("Timer started BEFORE", newValue)
      }
      else{ //Запускаем таймер
        log.info("Timer NEED started", newValue)
        timerId = setTimeout(function () { //Начинаем описывать таймер
          log.info("VALUE BIGGER over", debounceTime, " ms") //тут можно описать требуемое действие
          timerId = null; //Сбрасываем идентификатор отработавшего таймера
        }, debounceTime);
      }
    }
    else{ //Если значение МЕНЬШЕ уставки
      if (timerId){ //Если таймер УЖЕ есть
        log.info("Kill timer", timerId);
        clearTimeout(timerId); //останавливем таймер
        timerId = null; //Сбрасываем идентификатор таймера
      }
    }
  }
})

Замечательно, только как забубенить массив-то из таймеров?! ))))
Ни Set, ни Map не пашут.

А зачем массив? Таймер создавать-запускать в функции, которая отрабатывает по trackMqtt.

Таймер на каждый датчик же, не-се па? У меня сейчас четыре хлопают, надо смочить. )

Таймер создавать при необходимсоти же, динамически.
Единственное - запомнить имя топика и timerId. Например в массиве. и при повторном срабатывании проверять - если timerId не ноль а ошибки уже нет - то убивать таймер и обнулять его timerId

Прррраааавильно. Поэтому нужен хеш timerid = map(“topicname”);
Как?..

Завтра, думаю, напишу…

Не, я так долго не умею думать.

var timeout = 600;
var tids = [0];
var tnames = ['0'];
var i;
var t;
var tid;
trackMqtt("/devices/+/controls/+/meta/error", function(message){
  t = message.topic;
  t = t.split("/")[2];
  if (message.value != "") {
  	log.info("sensor: {} died".format(t));
    tid = setTimeout(function () {
          i = tids.indexOf(tid);
	      tids.splice(i, 1); 
          t = tnames.splice(i, 1);
          log.error("Hey, the sensor {} is dead!!! Call the tech!".format(t));
        }, timeout);
    tids.push(tid); tnames.push(t);
  } else {
    i = tnames.indexOf(t);
    if (i > 0) {              // we could kill this line when timer fired 
    	clearTimeout(tids[i]);
	        tids.splice(i, 1); tnames.splice(i, 1);
    }  
  	log.info("sensor: {} alive".format(t));
  }
});

Есть одно скользкое место. Запоминается ли переменная tid внутри функции коллбека (параметров она не имеет, увы). Пока, вроде бы, ДА, но из кода это совершенно не очевидно.

И вообще, как внутри коллбека надежно узнать, каким именно таймером его выстрелило? Что-то завяз. В стандартном js коллбеку можно послать доп. параметр (значение после таймаута в вызове setTimeout). Ваш движок на это не ругается, но значение отдает только undef.

Починил.

var timeout = 600;
var tids = [0];
var tnames = ['0'];
var i;
var t;
var tid;

log.info("--- start sensor tracker");

var __nativeST__ = setTimeout;
setTimeout = function(vCallback, nDelay /*, argumentToPass1, argumentToPass2, etc. */ ) {
 	 var aArgs = Array.prototype.slice.call(arguments, 2);
     return __nativeST__(vCallback instanceof Function ? function() {
        vCallback.apply(null, aArgs);
      } : vCallback, nDelay);
}; 

trackMqtt("/devices/+/controls/+/meta/error", function(message){
  t = message.topic;
  t = t.split("/")[2];
  if (message.value != "") {
  	log.info("sensor: {} sick".format(t));
	tid = setTimeout(function (topicname) {
          i = tnames.indexOf(topicname);
          tids.splice(i, 1); tnames.splice(i, 1);      // purge the timer record
          log.error("Hey, the sensor {} is dead!!! Call the tech!".format(topicname));
        }, timeout, t);
    tids.push(tid); tnames.push(t);
  } else {
    i = tnames.indexOf(t);
    if (i > 0) {             // we could have killed this rec when timer fired 
    	clearTimeout(tids[i]);
    	tids.splice(i, 1); tnames.splice(i, 1);
    }
  	log.info("sensor: {} alive".format(t));
  }
});
1 симпатия

По поводу “дребезга” в топике ошибки, в какой момент в топик /meta/error выставляется признак w? Сразу в момент неудачной попытки записи или уже после того, как драйвер совершил несколько неудачных попыток записать значение на устройство?

Да, сразу же: либо по таймауту (ответ на запрос не получен) либо по вернувщейся ошибке.

Строго говоря, для операции записи возможно 3 ошибочных исхода:

  1. Вернулся ответ с ошибкой
  2. Таймаут (ответ на запрос не получен)
  3. Получен ответ с неверной CRC

Расскажите, пожалуйста, подробнее алгоритм, как драйвер реагирует на каждую из этих ситуаций, наверняка реакция разная. Интересует в каких из этих случаев реализована переотправка запроса записи, с каким интервалом, сколько попыток, что происходит когда попытки исчерпаны.
Также заметил, что иногда в топике /meta/error появляется значение “rw” - в каком случае драйвер его выставляет? Значение “w” (без “r”) пока не наблюдалось - оно возможно?

Если есть отличия в логике выставления признаков ошибки “r” и “w” у драйверов wb-mqtt-serial и wb-mqtt-gpio, опишите их, пожалуйста, тоже.

  1. w - означает, что запись в регистр не удалась, не важно по какой причине.
  2. r - неудалось прочитать регистр. Опять же причина не важна.
  3. wr - ни записать, ни прочитать регистр не получилось.
  4. Если запись в регистр инициирована через MQTT, публикацией значения в соответствующий /on топик, то сейчас делается одна попытка записи.
  5. wb-mqtt-serial и wb-mqtt-gpio работают одинаково.
1 симпатия