# WB7 wb-2304 wb-rules последние, таймеры и дедлайн

**URL:** <https://support.wirenboard.com/t/wb7-wb-2304-wb-rules-poslednie-tajmery-i-dedlajn/14866>\
**Category:** Rule Engine\
**Tags:** wb-rules\
**Created:** [April 13, 2023, 9:37am UTC](https://support.wirenboard.com/t/wb7-wb-2304-wb-rules-poslednie-tajmery-i-dedlajn/14866 "2023-04-13T09:37:25Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![Vini74](https://support.wirenboard.com/user_avatar/support.wirenboard.com/vini74/32/5479_2.png) [@Vini74](https://support.wirenboard.com/u/Vini74)\
**Post date:** [April 13, 2023, 9:37am UTC](https://support.wirenboard.com/t/wb7-wb-2304-wb-rules-poslednie-tajmery-i-dedlajn/14866/1 "2023-04-13T09:37:25Z")

</div>

Здрасьте! Вот прям ночь не спали. С утра написал проверку.  
Садимся за веб интерфейс и дергаем таймеры на вкл выкл… минуты 3-5.  
И оно медленно умирает. Основная проблема это огромная задержка на реакцию правил. Например на переключатели в примере.  
Я слишком многого требую от скорострельности нашего четырёхъядерного калькулятора?

И в догонку. А как к таймеру через строковую переменную обращаться? А то код кривой получился…

```auto
var dn = "TT_01";
var dt = new Array();
var TT_01_PERIOD = 300;

var BUZ_DURATION = 200; // мс,
dt[0] = new Date();

startTicker("debug_sec_timer", 1000);

// Основной модуль
defineRule({
  when: function () { return timers.debug_sec_timer.firing; },
  then: function () {
    log.info(Math.round((new Date() - dt[0]) / 10) / 100, " сек.");
    dt[0] = new Date();
  }
});

defineVirtualDevice(dn, {
  title: dn,
  cells: {
    T1: { // 
      title: "T1",
      type: "switch",
      value: false,
      readonly: false,
      defaultvalue: true,
      order: 1
    },
    S1: { // 
      title: "S1",
      type: "text",
      value: "blank",
      readonly: true,
      defaultvalue: true,
      order: 101
    },
    T2: { // 
      title: "T2",
      type: "switch",
      value: false,
      readonly: false,
      defaultvalue: true,
      order: 2
    },
    S2: { // 
      title: "S2",
      type: "text",
      value: "blank",
      readonly: true,
      defaultvalue: true,
      order: 102
    },
    T3: { // 
      title: "T3",
      type: "switch",
      value: false,
      readonly: false,
      defaultvalue: true,
      order: 3
    },
    S3: { // 
      title: "S3",
      type: "text",
      value: "blank",
      readonly: true,
      defaultvalue: true,
      order: 103
    },
    T4: { // 
      title: "T4",
      type: "switch",
      value: false,
      readonly: false,
      defaultvalue: true,
      order: 4
    },
    S4: { // 
      title: "S4",
      type: "text",
      value: "blank",
      readonly: true,
      defaultvalue: true,
      order: 104
    },
    T5: { // 
      title: "T5",
      type: "switch",
      value: false,
      readonly: false,
      defaultvalue: true,
      order: 5
    },
    S5: { // 
      title: "S5",
      type: "text",
      value: "blank",
      readonly: true,
      defaultvalue: true,
      order: 105
    },
    T6: { // 
      title: "T6",
      type: "switch",
      value: false,
      readonly: false,
      defaultvalue: true,
      order: 6
    },
    S6: { // 
      title: "S6",
      type: "text",
      value: "blank",
      readonly: true,
      defaultvalue: true,
      order: 106
    },
    T7: { // 
      title: "T7",
      type: "switch",
      value: false,
      readonly: false,
      defaultvalue: true,
      order: 7
    },
    S7: { // 
      title: "S7",
      type: "text",
      value: "blank",
      readonly: true,
      defaultvalue: true,
      order: 107
    },
    T8: { // 
      title: "T8",
      type: "switch",
      value: false,
      readonly: false,
      defaultvalue: true,
      order: 8
    },
    S8: { // 
      title: "S8",
      type: "text",
      value: "blank",
      readonly: true,
      defaultvalue: true,
      order: 108
    },
    T9: { // 
      title: "T9",
      type: "switch",
      value: false,
      readonly: false,
      defaultvalue: true,
      order: 9
    },
    S9: { // 
      title: "S9",
      type: "text",
      value: "blank",
      readonly: true,
      defaultvalue: true,
      order: 109
    },
    T10: { // 
      title: "T10",
      type: "switch",
      value: false,
      readonly: false,
      defaultvalue: true,
      order: 10
    },
    S10: { // 
      title: "S10",
      type: "text",
      value: "blank",
      readonly: true,
      defaultvalue: true,
      order: 110
    }
  },
});

defineRule("T1", {
  whenChanged: [dn + "/T1"],
  then: function (newValue, devName, cellName) {
    log("Правило: {}.{}={}", devName, cellName, newValue) // вывод сообщения в лог   
    if (newValue == true) {
      startTicker("TT_01_T1", TT_01_PERIOD);
      dt[1] = new Date();
    }
    else
      timers.TT_01_T1.stop();
  }
});

defineRule("T2", {
  whenChanged: [dn + "/T2"],
  then: function (newValue, devName, cellName) {
    log("Правило: {}.{}={}", devName, cellName, newValue) // вывод сообщения в лог   
    if (newValue == true) {
      startTicker("TT_01_T2", TT_01_PERIOD);
      dt[2] = new Date();
    }
    else
      timers.TT_01_T2.stop();
  }
});

defineRule("T3", {
  whenChanged: [dn + "/T3"],
  then: function (newValue, devName, cellName) {
    log("Правило: {}.{}={}", devName, cellName, newValue) // вывод сообщения в лог   
    if (newValue == true) {
      startTicker("TT_01_T3", TT_01_PERIOD);
      dt[3] = new Date();
    }
    else
      timers.TT_01_T3.stop();
  }
});

defineRule("T4", {
  whenChanged: [dn + "/T4"],
  then: function (newValue, devName, cellName) {
    log("Правило: {}.{}={}", devName, cellName, newValue) // вывод сообщения в лог   
    if (newValue == true) {
      startTicker("TT_01_T4", TT_01_PERIOD);
      dt[4] = new Date();
    }
    else
      timers.TT_01_T4.stop();
  }
});

defineRule("T5", {
  whenChanged: [dn + "/T5"],
  then: function (newValue, devName, cellName) {
    log("Правило: {}.{}={}", devName, cellName, newValue) // вывод сообщения в лог   
    if (newValue == true) {
      startTicker("TT_01_T5", TT_01_PERIOD);
      dt[5] = new Date();
    }
    else
      timers.TT_01_T5.stop();
  }
});

defineRule("T6", {
  whenChanged: [dn + "/T6"],
  then: function (newValue, devName, cellName) {
    log("Правило: {}.{}={}", devName, cellName, newValue) // вывод сообщения в лог   
    if (newValue == true) {
      startTicker("TT_01_T6", TT_01_PERIOD);
      dt[6] = new Date();
    }
    else
      timers.TT_01_T6.stop();
  }
});

defineRule("T7", {
  whenChanged: [dn + "/T7"],
  then: function (newValue, devName, cellName) {
    log("Правило: {}.{}={}", devName, cellName, newValue) // вывод сообщения в лог   
    if (newValue == true) {
      startTicker("TT_01_T7", TT_01_PERIOD);
      dt[7] = new Date();
    }
    else
      timers.TT_01_T7.stop();
  }
});

defineRule("T8", {
  whenChanged: [dn + "/T8"],
  then: function (newValue, devName, cellName) {
    log("Правило: {}.{}={}", devName, cellName, newValue) // вывод сообщения в лог   
    if (newValue == true) {
      startTicker("TT_01_T8", TT_01_PERIOD);
      dt[8] = new Date();
    }
    else
      timers.TT_01_T8.stop();
  }
});

defineRule("T9", {
  whenChanged: [dn + "/T9"],
  then: function (newValue, devName, cellName) {
    log("Правило: {}.{}={}", devName, cellName, newValue) // вывод сообщения в лог   
    if (newValue == true) {
      startTicker("TT_01_T9", TT_01_PERIOD);
      dt[9] = new Date();
    }
    else
      timers.TT_01_T9.stop();
  }
});

defineRule("T10", {
  whenChanged: [dn + "/T10"],
  then: function (newValue, devName, cellName) {
    log("Правило: {}.{}={}", devName, cellName, newValue) // вывод сообщения в лог   
    if (newValue == true) {
      startTicker("TT_01_T10", TT_01_PERIOD);
      dt[10] = new Date();
    }
    else
      timers.TT_01_T10.stop();
  }
});

// TIMER #1
defineRule({
  when: function () { return timers.TT_01_T1.firing; },
  then: function () {
    dtl = Math.round((new Date() - dt[1]) / 10) / 100;
    log("TT_01_T1 ", dtl, " сек.");
    dev[dn + "/S1"] = String(dtl);
    dt[1] = new Date();
  }
});

// TIMER #2
defineRule({
  when: function () { return timers.TT_01_T2.firing; },
  then: function () {
    dtl = Math.round((new Date() - dt[2]) / 10) / 100;
    log("TT_01_T2 ", dtl, " сек.");
    dev[dn + "/S2"] = String(dtl);
    dt[2] = new Date();
  }
});

// TIMER #3
defineRule({
  when: function () { return timers.TT_01_T3.firing; },
  then: function () {
    dtl = Math.round((new Date() - dt[3]) / 10) / 100;
    log("TT_01_T3 ", dtl, " сек.");
    dev[dn + "/S3"] = String(dtl);
    dt[3] = new Date();
  }
});

// TIMER #4
defineRule({
  when: function () { return timers.TT_01_T4.firing; },
  then: function () {
    dtl = Math.round((new Date() - dt[4]) / 10) / 100;
    log("TT_01_T4 ", dtl, " сек.");
    dev[dn + "/S4"] = String(dtl);
    dt[4] = new Date();
  }
});

// TIMER #5
defineRule({
  when: function () { return timers.TT_01_T5.firing; },
  then: function () {
    dtl = Math.round((new Date() - dt[5]) / 10) / 100;
    log("TT_01_T5 ", dtl, " сек.");
    dev[dn + "/S5"] = String(dtl);
    dt[5] = new Date();
  }
});

// TIMER #6
defineRule({
  when: function () { return timers.TT_01_T6.firing; },
  then: function () {
    dtl = Math.round((new Date() - dt[6]) / 10) / 100;
    log("TT_01_T6 ", dtl, " сек.");
    dev[dn + "/S6"] = String(dtl);
    dt[6] = new Date();
  }
});
// TIMER #7
defineRule({
  when: function () { return timers.TT_01_T7.firing; },
  then: function () {
    dtl = Math.round((new Date() - dt[7]) / 10) / 100;
    log("TT_01_T7 ", dtl, " сек.");
    dev[dn + "/S7"] = String(dtl);
    dt[7] = new Date();
  }
});
// TIMER #8
defineRule({
  when: function () { return timers.TT_01_T8.firing; },
  then: function () {
    dtl = Math.round((new Date() - dt[8]) / 10) / 100;
    log("TT_01_T8 ", dtl, " сек.");
    dev[dn + "/S8"] = String(dtl);
    dt[8] = new Date();
  }
});
// TIMER #9
defineRule({
  when: function () { return timers.TT_01_T9.firing; },
  then: function () {
    dtl = Math.round((new Date() - dt[9]) / 10) / 100;
    log("TT_01_T9 ", dtl, " сек.");
    dev[dn + "/S9"] = String(dtl);
    dt[9] = new Date();
  }
});
// TIMER #10
defineRule({
  when: function () { return timers.TT_01_T10.firing; },
  then: function () {
    dtl = Math.round((new Date() - dt[10]) / 10) / 100;
    log("TT_01_T10 ", dtl, " сек.");
    dev[dn + "/S10"] = String(dtl);
    dt[10] = new Date();
  }
});

```

---

<div class="post-metadata">

**Author:** ![Vini74](https://support.wirenboard.com/user_avatar/support.wirenboard.com/vini74/32/5479_2.png) [@Vini74](https://support.wirenboard.com/u/Vini74)\
**Post date:** [April 13, 2023, 1:38pm UTC](https://support.wirenboard.com/t/wb7-wb-2304-wb-rules-poslednie-tajmery-i-dedlajn/14866/2 "2023-04-13T13:38:06Z")

</div>

Поговорю пока сам с собой.  
Вроде для данного примера я понял как избежать смерти рулесов. Тут все достаточно просто. Даже на 10 таймерах в 100мс все вроде работает. Но как подобное реализовать для `setInterval(callback, milliseconds)` ?  
вот решение для `startTicker` из примера выше.

```auto
/ TIMER #1
defineRule({
  when: function () { return timers.TT_01_T1.firing; },
  then: function () {
    timers.TT_01_T1.stop();
    dtl = Math.round((new Date() - dt[1]) / 10) / 100;
    //log("TT_01_T1 ", dtl, " сек.");
    dev[dn + "/S1"] = String(dtl);
    dt[1] = new Date();
    startTicker("TT_01_T1", TT_01_PERIOD);
  }
});

```

---

<div class="post-metadata">

**Author:** ![Vini74](https://support.wirenboard.com/user_avatar/support.wirenboard.com/vini74/32/5479_2.png) [@Vini74](https://support.wirenboard.com/u/Vini74)\
**Post date:** [April 13, 2023, 1:48pm UTC](https://support.wirenboard.com/t/wb7-wb-2304-wb-rules-poslednie-tajmery-i-dedlajn/14866/3 "2023-04-13T13:48:11Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![BrainRoot](https://avatars.discourse-cdn.com/v2/letter/b/c2a13f/32.png) [@BrainRoot](https://support.wirenboard.com/u/BrainRoot)\
**Post date:** [April 13, 2023, 1:51pm UTC](https://support.wirenboard.com/t/wb7-wb-2304-wb-rules-poslednie-tajmery-i-dedlajn/14866/4 "2023-04-13T13:51:09Z")

</div>

Добрый день.  
Попробую воспроизвести сейчас.

---

<div class="post-metadata">

**Author:** ![BrainRoot](https://avatars.discourse-cdn.com/v2/letter/b/c2a13f/32.png) [@BrainRoot](https://support.wirenboard.com/u/BrainRoot)\
**Post date:** [April 14, 2023, 5:45pm UTC](https://support.wirenboard.com/t/wb7-wb-2304-wb-rules-poslednie-tajmery-i-dedlajn/14866/5 "2023-04-14T17:45:12Z")

</div>

Уже больше суток работают…

---

<div class="post-metadata">

**Author:** ![Vini74](https://support.wirenboard.com/user_avatar/support.wirenboard.com/vini74/32/5479_2.png) [@Vini74](https://support.wirenboard.com/u/Vini74)\
**Post date:** [April 15, 2023, 12:56pm UTC](https://support.wirenboard.com/t/wb7-wb-2304-wb-rules-poslednie-tajmery-i-dedlajn/14866/6 "2023-04-15T12:56:11Z")

</div>

с какой частотой? поставьте 100 или 50 мс.  
На включение выключение таймеров из вебки реагирует?  
Не стоит ждать когда именно пример с var TT\_01\_PERIOD = 300; сломается.  
Тут зависит от фоновых процессов…  
Хватает нескольких минут при правильных значениях.

---

<div class="post-metadata">

**Author:** ![BrainRoot](https://avatars.discourse-cdn.com/v2/letter/b/c2a13f/32.png) [@BrainRoot](https://support.wirenboard.com/u/BrainRoot)\
**Post date:** [April 17, 2023, 9:42am UTC](https://support.wirenboard.com/t/wb7-wb-2304-wb-rules-poslednie-tajmery-i-dedlajn/14866/7 "2023-04-17T09:42:49Z")

</div>

Поставил 50. Таймеры - срабатываютт, но да, нагрузка на CPU больше одного ядра и остановка таймера отрабатывает силно не сразу.  
А для какой цели испоьзуются такие значения? На практике не слакивался, минимальные таймеры использовал как раз 250мс.

---

<div class="post-metadata">

**Author:** ![Vini74](https://support.wirenboard.com/user_avatar/support.wirenboard.com/vini74/32/5479_2.png) [@Vini74](https://support.wirenboard.com/u/Vini74)\
**Post date:** [April 17, 2023, 10:32am UTC](https://support.wirenboard.com/t/wb7-wb-2304-wb-rules-poslednie-tajmery-i-dedlajn/14866/8 "2023-04-17T10:32:52Z")

</div>

А у нас на 500-1000мс таймерах в продакшене такая картина рисовалась. Я же не могу выгрузить сюда кучу кода, в котором никто не разберется. Поэтому пришлось сделать простенький пример, и что бы он показательно заработал, уменьшили в нем периоды таймеров. Поведение то ровно такое же. При этом на веб интерфейсе значения бегут шустро. А вот правила - да. Начинают тормозить не по детски.

---

<div class="post-metadata">

**Author:** ![Vini74](https://support.wirenboard.com/user_avatar/support.wirenboard.com/vini74/32/5479_2.png) [@Vini74](https://support.wirenboard.com/u/Vini74)\
**Post date:** [April 17, 2023, 10:34am UTC](https://support.wirenboard.com/t/wb7-wb-2304-wb-rules-poslednie-tajmery-i-dedlajn/14866/9 "2023-04-17T10:34:43Z")

</div>

Вот последний пример тестового кода. Что-бы было.

```auto
var dn = "TT_01";
var DEBUG = 1;
var dt = new Array();
var tms = new Array();
var TT_01_PERIOD = 10;

dt[0] = new Date();

startTicker("debug_sec_timer", 1000);

// Основной модуль
defineRule({
  when: function () { return timers.debug_sec_timer.firing; },
  then: function () {
    debug("MAIN ", Math.round((new Date() - dt[0]) / 10) / 100, " сек.");
    dt[0] = new Date();

  }
});

defineVirtualDevice(dn, {
  title: dn,
  cells: {
    T1: { // 
      title: "T1",
      type: "switch",
      value: false,
      readonly: false,
      defaultvalue: true,
      order: 1
    },
    S1: { // 
      title: "S1",
      type: "text",
      value: "blank",
      readonly: true,
      defaultvalue: true,
      order: 101
    },
    T2: { // 
      title: "T2",
      type: "switch",
      value: false,
      readonly: false,
      defaultvalue: true,
      order: 2
    },
    S2: { // 
      title: "S2",
      type: "text",
      value: "blank",
      readonly: true,
      defaultvalue: true,
      order: 102
    },
    T3: { // 
      title: "T3",
      type: "switch",
      value: false,
      readonly: false,
      defaultvalue: true,
      order: 3
    },
    S3: { // 
      title: "S3",
      type: "text",
      value: "blank",
      readonly: true,
      defaultvalue: true,
      order: 103
    },
    T4: { // 
      title: "T4",
      type: "switch",
      value: false,
      readonly: false,
      defaultvalue: true,
      order: 4
    },
    S4: { // 
      title: "S4",
      type: "text",
      value: "blank",
      readonly: true,
      defaultvalue: true,
      order: 104
    },
    T5: { // 
      title: "T5",
      type: "switch",
      value: false,
      readonly: false,
      defaultvalue: true,
      order: 5
    },
    S5: { // 
      title: "S5",
      type: "text",
      value: "blank",
      readonly: true,
      defaultvalue: true,
      order: 105
    },
    T6: { // 
      title: "T6",
      type: "switch",
      value: false,
      readonly: false,
      defaultvalue: true,
      order: 6
    },
    S6: { // 
      title: "S6",
      type: "text",
      value: "blank",
      readonly: true,
      defaultvalue: true,
      order: 106
    },
    T7: { // 
      title: "T7",
      type: "switch",
      value: false,
      readonly: false,
      defaultvalue: true,
      order: 7
    },
    S7: { // 
      title: "S7",
      type: "text",
      value: "blank",
      readonly: true,
      defaultvalue: true,
      order: 107
    },
    T8: { // 
      title: "T8",
      type: "switch",
      value: false,
      readonly: false,
      defaultvalue: true,
      order: 8
    },
    S8: { // 
      title: "S8",
      type: "text",
      value: "blank",
      readonly: true,
      defaultvalue: true,
      order: 108
    },
    T9: { // 
      title: "T9",
      type: "switch",
      value: false,
      readonly: false,
      defaultvalue: true,
      order: 9
    },
    S9: { // 
      title: "S9",
      type: "text",
      value: "blank",
      readonly: true,
      defaultvalue: true,
      order: 109
    },
    T10: { // 
      title: "T10",
      type: "switch",
      value: false,
      readonly: false,
      defaultvalue: true,
      order: 10
    },
    S10: { // 
      title: "S10",
      type: "text",
      value: "blank",
      readonly: true,
      defaultvalue: true,
      order: 110
    }
  },
});

//RULES
// CHNAGE!!!!
dev_index = 1;
defineRule("T" + dev_index, {
  whenChanged: [dn + "/T" + dev_index],
  then: function (newValue, devName, cellName) {
    // CHNAGE!!!!
    var dev_index = 1;
    var timer_name = dn + "_T" + dev_index;
    debug("Правило: {}.{} = {}", devName, cellName, newValue) // вывод сообщения в лог   
    if (newValue == true) {
      startTicker(timer_name, TT_01_PERIOD);
      dt[dev_index] = new Date();
    }
    else {
      _wbStopTimer(timer_name);
      debug(cellName + " stoped");
    }
    dev[dn + "/S" + dev_index] = "0";
  }
});

defineRule({
  // CHNAGE!!!!
  when: function () { return _wbCheckCurrentTimer(dn + "_T1"); },
  then: function () {
    // CHNAGE!!!!
    var dev_index = 1;
    var timer_name = dn + "_T" + dev_index;
    _wbStopTimer(timer_name);
    dtl = Math.round((new Date() - dt[dev_index]) / 10) / 100;
    if (DEBUG > 4) debug(dn + "1_T" + dev_index + " " + dtl + " сек.");
    dev[dn + "/S" + dev_index] = String(dtl);
    dt[dev_index] = new Date();
    startTicker(timer_name, TT_01_PERIOD);
  }
});

// CHNAGE!!!!
dev_index = 2;
defineRule("T" + dev_index, {
  whenChanged: [dn + "/T" + dev_index],
  then: function (newValue, devName, cellName) {
    // CHNAGE!!!!
    var dev_index = 2;
    var timer_name = dn + "_T" + dev_index;
    debug("Правило: {}.{} = {}", devName, cellName, newValue) // вывод сообщения в лог   
    if (newValue == true) {
      startTicker(timer_name, TT_01_PERIOD);
      dt[dev_index] = new Date();
    }
    else {
      _wbStopTimer(timer_name);
      debug(cellName + " stoped");
    }
    dev[dn + "/S" + dev_index] = "0";
  }
});

defineRule({
  // CHNAGE!!!!
  when: function () { return _wbCheckCurrentTimer(dn + "_T2"); },
  then: function () {
    // CHNAGE!!!!
    var dev_index = 2;
    var timer_name = dn + "_T" + dev_index;
    _wbStopTimer(timer_name);
    dtl = Math.round((new Date() - dt[dev_index]) / 10) / 100;
    if (DEBUG > 4) debug(dn + "1_T" + dev_index + " " + dtl + " сек.");
    dev[dn + "/S" + dev_index] = String(dtl);
    dt[dev_index] = new Date();
    startTicker(timer_name, TT_01_PERIOD);
  }
});

// CHNAGE!!!!
dev_index = 3;
defineRule("T" + dev_index, {
  whenChanged: [dn + "/T" + dev_index],
  then: function (newValue, devName, cellName) {
    // CHNAGE!!!!
    var dev_index = 3;
    var timer_name = dn + "_T" + dev_index;
    debug("Правило: {}.{} = {}", devName, cellName, newValue) // вывод сообщения в лог   
    if (newValue == true) {
      startTicker(timer_name, TT_01_PERIOD);
      dt[dev_index] = new Date();
    }
    else {
      _wbStopTimer(timer_name);
      debug(cellName + " stoped");
    }
    dev[dn + "/S" + dev_index] = "0";
  }
});

defineRule({
  // CHNAGE!!!!
  when: function () { return _wbCheckCurrentTimer(dn + "_T3"); },
  then: function () {
    // CHNAGE!!!!
    var dev_index = 3;
    var timer_name = dn + "_T" + dev_index;
    _wbStopTimer(timer_name);
    dtl = Math.round((new Date() - dt[dev_index]) / 10) / 100;
    if (DEBUG > 4) debug(dn + "1_T" + dev_index + " " + dtl + " сек.");
    dev[dn + "/S" + dev_index] = String(dtl);
    dt[dev_index] = new Date();
    startTicker(timer_name, TT_01_PERIOD);
  }
});

// CHNAGE!!!!
dev_index = 4;
defineRule("T" + dev_index, {
  whenChanged: [dn + "/T" + dev_index],
  then: function (newValue, devName, cellName) {
    // CHNAGE!!!!
    var dev_index = 4;
    var timer_name = dn + "_T" + dev_index;
    debug("Правило: {}.{} = {}", devName, cellName, newValue) // вывод сообщения в лог   
    if (newValue == true) {
      startTicker(timer_name, TT_01_PERIOD);
      dt[dev_index] = new Date();
    }
    else {
      _wbStopTimer(timer_name);
      debug(cellName + " stoped");
    }
    dev[dn + "/S" + dev_index] = "0";
  }
});

defineRule({
  // CHNAGE!!!!
  when: function () { return _wbCheckCurrentTimer(dn + "_T4"); },
  then: function () {
    // CHNAGE!!!!
    var dev_index = 4;
    var timer_name = dn + "_T" + dev_index;
    _wbStopTimer(timer_name);
    dtl = Math.round((new Date() - dt[dev_index]) / 10) / 100;
    if (DEBUG > 4) debug(dn + "1_T" + dev_index + " " + dtl + " сек.");
    dev[dn + "/S" + dev_index] = String(dtl);
    dt[dev_index] = new Date();
    startTicker(timer_name, TT_01_PERIOD);
  }
});

// CHNAGE!!!!
dev_index = 5;
defineRule("T" + dev_index, {
  whenChanged: [dn + "/T" + dev_index],
  then: function (newValue, devName, cellName) {
    // CHNAGE!!!!
    var dev_index = 5;
    var timer_name = dn + "_T" + dev_index;
    debug("Правило: {}.{} = {}", devName, cellName, newValue) // вывод сообщения в лог   
    if (newValue == true) {
      startTicker(timer_name, TT_01_PERIOD);
      dt[dev_index] = new Date();
    }
    else {
      _wbStopTimer(timer_name);
      debug(cellName + " stoped");
    }
    dev[dn + "/S" + dev_index] = "0";
  }
});

defineRule({
  // CHNAGE!!!!
  when: function () { return _wbCheckCurrentTimer(dn + "_T5"); },
  then: function () {
    // CHNAGE!!!!
    var dev_index = 5;
    var timer_name = dn + "_T" + dev_index;
    _wbStopTimer(timer_name);
    dtl = Math.round((new Date() - dt[dev_index]) / 10) / 100;
    if (DEBUG > 4) debug(dn + "1_T" + dev_index + " " + dtl + " сек.");
    dev[dn + "/S" + dev_index] = String(dtl);
    dt[dev_index] = new Date();
    startTicker(timer_name, TT_01_PERIOD);
  }
});

// CHNAGE!!!!
dev_index = 6;
defineRule("T" + dev_index, {
  whenChanged: [dn + "/T" + dev_index],
  then: function (newValue, devName, cellName) {
    // CHNAGE!!!!
    var dev_index = 6;
    var timer_name = dn + "_T" + dev_index;
    debug("Правило: {}.{} = {}", devName, cellName, newValue) // вывод сообщения в лог   
    if (newValue == true) {
      startTicker(timer_name, TT_01_PERIOD);
      dt[dev_index] = new Date();
    }
    else {
      _wbStopTimer(timer_name);
      debug(cellName + " stoped");
    }
    dev[dn + "/S" + dev_index] = "0";
  }
});

defineRule({
  // CHNAGE!!!!
  when: function () { return _wbCheckCurrentTimer(dn + "_T6"); },
  then: function () {
    // CHNAGE!!!!
    var dev_index = 6;
    var timer_name = dn + "_T" + dev_index;
    _wbStopTimer(timer_name);
    dtl = Math.round((new Date() - dt[dev_index]) / 10) / 100;
    if (DEBUG > 4) debug(dn + "1_T" + dev_index + " " + dtl + " сек.");
    dev[dn + "/S" + dev_index] = String(dtl);
    dt[dev_index] = new Date();
    startTicker(timer_name, TT_01_PERIOD);
  }
});

// CHNAGE!!!!
dev_index = 7;
defineRule("T" + dev_index, {
  whenChanged: [dn + "/T" + dev_index],
  then: function (newValue, devName, cellName) {
    // CHNAGE!!!!
    var dev_index = 7;
    var timer_name = dn + "_T" + dev_index;
    debug("Правило: {}.{} = {}", devName, cellName, newValue) // вывод сообщения в лог   
    if (newValue == true) {
      startTicker(timer_name, TT_01_PERIOD);
      dt[dev_index] = new Date();
    }
    else {
      _wbStopTimer(timer_name);
      debug(cellName + " stoped");
    }
    dev[dn + "/S" + dev_index] = "0";
  }
});

defineRule({
  // CHNAGE!!!!
  when: function () { return _wbCheckCurrentTimer(dn + "_T7"); },
  then: function () {
    // CHNAGE!!!!
    var dev_index = 7;
    var timer_name = dn + "_T" + dev_index;
    _wbStopTimer(timer_name);
    dtl = Math.round((new Date() - dt[dev_index]) / 10) / 100;
    if (DEBUG > 4) debug(dn + "1_T" + dev_index + " " + dtl + " сек.");
    dev[dn + "/S" + dev_index] = String(dtl);
    dt[dev_index] = new Date();
    startTicker(timer_name, TT_01_PERIOD);
  }
});
// CHNAGE!!!!
dev_index = 8;
defineRule("T" + dev_index, {
  whenChanged: [dn + "/T" + dev_index],
  then: function (newValue, devName, cellName) {
    // CHNAGE!!!!
    var dev_index = 8;
    var timer_name = dn + "_T" + dev_index;
    debug("Правило: {}.{} = {}", devName, cellName, newValue) // вывод сообщения в лог   
    if (newValue == true) {
      startTicker(timer_name, TT_01_PERIOD);
      dt[dev_index] = new Date();
    }
    else {
      _wbStopTimer(timer_name);
      debug(cellName + " stoped");
    }
    dev[dn + "/S" + dev_index] = "0";
  }
});

defineRule({
  // CHNAGE!!!!
  when: function () { return _wbCheckCurrentTimer(dn + "_T8"); },
  then: function () {
    // CHNAGE!!!!
    var dev_index = 8;
    var timer_name = dn + "_T" + dev_index;
    _wbStopTimer(timer_name);
    dtl = Math.round((new Date() - dt[dev_index]) / 10) / 100;
    if (DEBUG > 4) debug(dn + "1_T" + dev_index + " " + dtl + " сек.");
    dev[dn + "/S" + dev_index] = String(dtl);
    dt[dev_index] = new Date();
    startTicker(timer_name, TT_01_PERIOD);
  }
});
// CHNAGE!!!!
dev_index = 9;
defineRule("T" + dev_index, {
  whenChanged: [dn + "/T" + dev_index],
  then: function (newValue, devName, cellName) {
    // CHNAGE!!!!
    var dev_index = 9;
    var timer_name = dn + "_T" + dev_index;
    debug("Правило: {}.{} = {}", devName, cellName, newValue) // вывод сообщения в лог   
    if (newValue == true) {
      startTicker(timer_name, TT_01_PERIOD);
      dt[dev_index] = new Date();
    }
    else {
      _wbStopTimer(timer_name);
      debug(cellName + " stoped");
    }
    dev[dn + "/S" + dev_index] = "0";
  }
});

defineRule({
  // CHNAGE!!!!
  when: function () { return _wbCheckCurrentTimer(dn + "_T9"); },
  then: function () {
    // CHNAGE!!!!
    var dev_index = 9;
    var timer_name = dn + "_T" + dev_index;
    _wbStopTimer(timer_name);
    dtl = Math.round((new Date() - dt[dev_index]) / 10) / 100;
    if (DEBUG > 4) debug(dn + "1_T" + dev_index + " " + dtl + " сек.");
    dev[dn + "/S" + dev_index] = String(dtl);
    dt[dev_index] = new Date();
    startTicker(timer_name, TT_01_PERIOD);
  }
});
// CHNAGE!!!!
dev_index = 10;
defineRule("T" + dev_index, {
  whenChanged: [dn + "/T" + dev_index],
  then: function (newValue, devName, cellName) {
    // CHNAGE!!!!
    var dev_index = 10;
    var timer_name = dn + "_T" + dev_index;
    debug("Правило: {}.{} = {}", devName, cellName, newValue) // вывод сообщения в лог   
    if (newValue == true) {
      startTicker(timer_name, TT_01_PERIOD);
      dt[dev_index] = new Date();
    }
    else {
      _wbStopTimer(timer_name);
      debug(cellName + " stoped");
    }
    dev[dn + "/S" + dev_index] = "0";
  }
});

defineRule({
  // CHNAGE!!!!
  when: function () { return _wbCheckCurrentTimer(dn + "_T10"); },
  then: function () {
    // CHNAGE!!!!
    var dev_index = 10;
    var timer_name = dn + "_T" + dev_index;
    _wbStopTimer(timer_name);
    dtl = Math.round((new Date() - dt[dev_index]) / 10) / 100;
    if (DEBUG > 4) debug(dn + "1_T" + dev_index + " " + dtl + " сек.");
    dev[dn + "/S" + dev_index] = String(dtl);
    dt[dev_index] = new Date();
    startTicker(timer_name, TT_01_PERIOD);
  }
});

```

---

<div class="post-metadata">

**Author:** ![Vini74](https://support.wirenboard.com/user_avatar/support.wirenboard.com/vini74/32/5479_2.png) [@Vini74](https://support.wirenboard.com/u/Vini74)\
**Post date:** [April 17, 2023, 10:57am UTC](https://support.wirenboard.com/t/wb7-wb-2304-wb-rules-poslednie-tajmery-i-dedlajn/14866/10 "2023-04-17T10:57:09Z")

</div>

И немного резюмируя. Похоже, что мы намудрили в коде и плохо посчитали все периодические циклы, их вложенность и скорость их выполнения. Понемногу эту ситуацию мы выправляем. Основная проблема в том, что при такой загрузке системы появляется очень большая задержка в обработке правил. Я так понимаю, что это ограничение JS. Приоритезацию тут сделать нельзя, а хотелось бы.

---

<div class="post-metadata">

**Author:** ![Vini74](https://support.wirenboard.com/user_avatar/support.wirenboard.com/vini74/32/5479_2.png) [@Vini74](https://support.wirenboard.com/u/Vini74)\
**Post date:** [April 17, 2023, 10:59am UTC](https://support.wirenboard.com/t/wb7-wb-2304-wb-rules-poslednie-tajmery-i-dedlajn/14866/11 "2023-04-17T10:59:39Z")

</div>

> [@Vini74](#):
>
> `_wbCheckCurrentTimer(dn + "_T2")`

И вопрос общего плана.  
Функции  
\_wbCheckCurrentTimer(string)  
и  
\_wbStopTimer(string)  
Я ведь могу использовать в коде? Документированных альтернатив я не нашел.

---

<div class="post-metadata">

**Author:** ![BrainRoot](https://avatars.discourse-cdn.com/v2/letter/b/c2a13f/32.png) [@BrainRoot](https://support.wirenboard.com/u/BrainRoot)\
**Post date:** [April 18, 2023, 7:46am UTC](https://support.wirenboard.com/t/wb7-wb-2304-wb-rules-poslednie-tajmery-i-dedlajn/14866/12 "2023-04-18T07:46:45Z")

</div>

> [@Vini74](#):
>
> Основная проблема в том, что при такой загрузке системы появляется очень большая задержка в обработке правил. Я так понимаю, что это ограничение JS.

Скорее текущего движка. В планах есть его очередной рефакторинг с заменой части кода.

> [@Vini74](#):
>
> Функции  
> \_wbCheckCurrentTimer(string)  
> и  
> \_wbStopTimer(string)  
> Я ведь могу использовать в коде?

Да, конечно.

---

<div class="post-metadata">

**Author:** ![Vini74](https://support.wirenboard.com/user_avatar/support.wirenboard.com/vini74/32/5479_2.png) [@Vini74](https://support.wirenboard.com/u/Vini74)\
**Post date:** [April 19, 2023, 9:13am UTC](https://support.wirenboard.com/t/wb7-wb-2304-wb-rules-poslednie-tajmery-i-dedlajn/14866/13 "2023-04-19T09:13:54Z")

</div>

Рефакторинг это конечно не плохо. Но в продолжении философии организации правил для текущей версии движка есть такой вопрос:  
Вводная. (код мы написали и он у нас есть рабочий, но я крайне не уверен в его оптимальности)  
Итак, у нас есть исполнительный механизм. Будем честны - это щетка пола. Она в не рабочем состоянии находится в стене, закрытая крышкой. И крышка и щетка имеет привод и по 2 концевика на min и max. Что бы выполнить работу по помывке пола, необходимо выполнить следующую последовательность задач:

1. открыть крышку щетки. (до концевика на крышке)
2. дождаться открытия крышки щетки по концевику. Если крышка не открылась за 1с уходим в аварию.
3. Начать движение щетки по полу.
4. ждать пока щетка доедет до концевика max. Если не доехало за 10с уходим в аварию.
5. когда доехали щеткой до MAX, готовимся к пути назад:  
5.1 выключаем питание щетки.  
5.2 пауза не менее 100мс  
5.3 переключаем полярность  
5.4 пауза не менее 100мс  
5.5 включаем питание щетки и едем назад.
6. Доехали назад до концевика МИН. если за 10 сек назад не доехали - в аварию.
7. Закрыли крышку щетки. если крышка за 1с не закрылась - авария.

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

---

<div class="post-metadata">

**Author:** ![Vini74](https://support.wirenboard.com/user_avatar/support.wirenboard.com/vini74/32/5479_2.png) [@Vini74](https://support.wirenboard.com/u/Vini74)\
**Post date:** [April 19, 2023, 9:16am UTC](https://support.wirenboard.com/t/wb7-wb-2304-wb-rules-poslednie-tajmery-i-dedlajn/14866/14 "2023-04-19T09:16:05Z")

</div>

А еще задачу можно усугубить, и перед аварией попытаться выполнить не закончившуюся операцию еще 2 раза.

---

<div class="post-metadata">

**Author:** ![BrainRoot](https://avatars.discourse-cdn.com/v2/letter/b/c2a13f/32.png) [@BrainRoot](https://support.wirenboard.com/u/BrainRoot)\
**Post date:** [April 19, 2023, 11:17am UTC](https://support.wirenboard.com/t/wb7-wb-2304-wb-rules-poslednie-tajmery-i-dedlajn/14866/15 "2023-04-19T11:17:13Z")

</div>

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

- Значение 1 - выполняется операция открытия крышки, в случае успеха флаг меняется на 2.
- Значение 2 - начинается движение щетки “туда”, успех (с несколькими попытками, возможно) - значение 3
- Движение щетки обратно, если успех - значение 4
- Закрытие крышки, если успех - то значение опять 0  
Ну и, соответственно уже для каждой из операций - функции, ее реализующие.  
Естественно, в случае “неудачи” - обработка и (или) оповещение. Например в случае неудачи шага 2 - пробуем шаг 3 (возврат щетки в исходное положение).  
Так, “шагами” у меня например приведение манипулятора в исходное состояние было сделано.

---

<div class="post-metadata">

**Author:** ![Vini74](https://support.wirenboard.com/user_avatar/support.wirenboard.com/vini74/32/5479_2.png) [@Vini74](https://support.wirenboard.com/u/Vini74)\
**Post date:** [April 19, 2023, 1:35pm UTC](https://support.wirenboard.com/t/wb7-wb-2304-wb-rules-poslednie-tajmery-i-dedlajn/14866/16 "2023-04-19T13:35:12Z")

</div>

Да, конечный автомат это наше все. А как таймеры и задержки то правильно добавлять и обрабатывать? я же в коде delay задать не могу. с таймерами еще куда ни шло, а вот как проще делать задержки, что бы не блокировать движок?  
У нас это каскадные setTimeout. Страшненько выглядит.

---

<div class="post-metadata">

**Author:** ![BrainRoot](https://avatars.discourse-cdn.com/v2/letter/b/c2a13f/32.png) [@BrainRoot](https://support.wirenboard.com/u/BrainRoot)\
**Post date:** [April 20, 2023, 10:42am UTC](https://support.wirenboard.com/t/wb7-wb-2304-wb-rules-poslednie-tajmery-i-dedlajn/14866/17 "2023-04-20T10:42:04Z")

</div>

Да тут несложно на самом деле.  
Запускаем таймер а в обработчик ему действие сразу.  
С тем же приводом - включаем реле, запускаем таймер. Либо сработает он, выдавая ошибку таймаута и выключая реле либо сработает правило концевика, в правиле будет остановлен таймер и выключено реле опять же.  
Кстати, выключать привод можно и аппаратно, заведя концевики на входы Modbus модуля реле.

---

<div class="post-metadata">

**Author:** ![Vini74](https://support.wirenboard.com/user_avatar/support.wirenboard.com/vini74/32/5479_2.png) [@Vini74](https://support.wirenboard.com/u/Vini74)\
**Post date:** [April 20, 2023, 11:31am UTC](https://support.wirenboard.com/t/wb7-wb-2304-wb-rules-poslednie-tajmery-i-dedlajn/14866/18 "2023-04-20T11:31:59Z")

</div>

В целом так мы на это и смотрим. Пока получается некая слабочитаемая структура кода, особенно если еще добавить в алгоритмы “если не доехали до концевика, попробуй еще 2 раза. и лишь потом выдавай ошибку.”  
Привод мы выключаем по комбинированному концевику, он механически отключает питание у привода, ну и как концевик работает. Скорость обмена то не предсказуемая. Механика рулит.

---

<div class="post-metadata">

**Author:** ![AlexandrD](https://support.wirenboard.com/user_avatar/support.wirenboard.com/alexandrd/32/6172_2.png) [@AlexandrD](https://support.wirenboard.com/u/AlexandrD)\
**Post date:** [April 21, 2023, 9:54pm UTC](https://support.wirenboard.com/t/wb7-wb-2304-wb-rules-poslednie-tajmery-i-dedlajn/14866/19 "2023-04-21T21:54:14Z")

</div>

1 запись была перенесена в новую тему: [Установка Wireguard](https://support.wirenboard.com/t/ustanovka-wireguard/14950)

---

<div class="post-metadata">

**Author:** ![system](https://support.wirenboard.com/uploads/default/original/2X/5/5ac90dc8a7bdff486d3494a19ec6aaa6f6cc5d36.png) [@system](https://support.wirenboard.com/u/system)\
**Post date:** [April 28, 2023, 9:54pm UTC](https://support.wirenboard.com/t/wb7-wb-2304-wb-rules-poslednie-tajmery-i-dedlajn/14866/20 "2023-04-28T21:54:29Z")

</div>

Эта тема была автоматически закрыта через 7 дней после последнего ответа. В ней больше нельзя отвечать.
