Задача на разминку - стучать в скаду, если отвалился какой-либо датчик - насовсем отвалился (некоторые “хлопают” раз в 5-100 минут, это нужно игнорировать).
Соотв надо отслеживать “/devices/+/controls/+/meta/error” и ставить таймер при появлении ашыпки на дивайсе, гасить его при пропадении, а при непропадении громко кричать.
Как изящнее прибить отслеживание топика meta/error к правилам?
Идея в том - что при срабатывании правила (появлении meta error) запускается таймер и если значение на момент завершения таймера ни разу не поменялось (остался error) - тогда уже точно срабатывание не единичное.
//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; //Сбрасываем идентификатор таймера
}
}
}
})
Таймер создавать при необходимсоти же, динамически.
Единственное - запомнить имя топика и timerId. Например в массиве. и при повторном срабатывании проверять - если timerId не ноль а ошибки уже нет - то убивать таймер и обнулять его timerId
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));
}
});
По поводу “дребезга” в топике ошибки, в какой момент в топик /meta/error выставляется признак w? Сразу в момент неудачной попытки записи или уже после того, как драйвер совершил несколько неудачных попыток записать значение на устройство?
Строго говоря, для операции записи возможно 3 ошибочных исхода:
Вернулся ответ с ошибкой
Таймаут (ответ на запрос не получен)
Получен ответ с неверной CRC
Расскажите, пожалуйста, подробнее алгоритм, как драйвер реагирует на каждую из этих ситуаций, наверняка реакция разная. Интересует в каких из этих случаев реализована переотправка запроса записи, с каким интервалом, сколько попыток, что происходит когда попытки исчерпаны.
Также заметил, что иногда в топике /meta/error появляется значение “rw” - в каком случае драйвер его выставляет? Значение “w” (без “r”) пока не наблюдалось - оно возможно?
Если есть отличия в логике выставления признаков ошибки “r” и “w” у драйверов wb-mqtt-serial и wb-mqtt-gpio, опишите их, пожалуйста, тоже.