Вопрос по правилам: как не запускать правила при первом запуске


#1

после перезагрузки контроллера часть правил запускается, потому что срабатывает onchange по сравнению с retained значениями. можно как-то отловить это и не пропускать отработку правил?


#2

Вопрос касается whenChanged?
Обработчик onchange не из wb-rules


#3

да, конечно, whenChanged


#4

whenChanged ничего не сравнивает, он просто выполняет заложенную функцию при изменении входного параметра или при перезапуске правила.
Можете на примере проиллюстрировать?


#5

да. есть радио кнопка vhome, у которой whenChanged выключает или выключает весь свет, например.

рестарт контроллера приводит к срабатыванию whenChanged, хотя нажатия не было.
рестарт движка правил к такому эффекту не приводит.

правило самое простое
defineRule( “targetrule” + rc, {
whenChanged: re.devname,
then:
(function( devname, target, devtarget ) {
return function( newValue, devName, cellName ) {
log( “on '” + devname + “’ change '” + target + “’ (” + devtarget + “)” + “nv={} dn={} cn={}”, newValue, devName, cellName );
dev[devtarget] = ! dev[devtarget];
};
})( re.devname, re.target, getTarget( re.target ) )
});

можно как-то отличить запуск правила при старте от запуска правила при событии?


#6

Ну на пример добавить проверку, что Current uptime больше минуты. Тогда в первую минуту после запуска правило работать не будет, за то и первое срабатывание будет проигнорировано.


#7

у меня стоит задержка 5 секунд после первого просмотра. минута много, но попробую, спасибо.


#8

Я обычно ставлю переменную-флаг при начальной инициализации программы, который при первом выполнении функции сбрасывается.

var initial = true;
.
.
.
if (initial) {  // если выполнение тела произошло по причине первоначальной загрузки сбрасываем флаг
initial = false;
} else {      // если выполнение кода произошло когда инициализация уже прошла, то выполняем действие
dev[devtarget] = ! dev[devtarget]; 
}
.
.

Изящнее было бы такую проверку делать сразу в whenChanged, но похоже это не предусмотрено синтаксисом команды.


#9

у меня в любом случае whanChanged генерится в обертке, добавить туда проверку не сложно. но как-то хотелось бы документированно понимать, что это вызов не по событию, а по first run.


#10

Скажите пожалуйста что за обертку используете для генерации кода?
В чем ее преимущество?
Где про этот способ можно получить информацию?


#11

обертка - это генерация правил на основе массива данных с описанием кто на что и как реагирует. просто мне так было удобно.

почитать - это функции JavaScript + clusure.


#12

На странице описания движка правил есть немного про обертки:
https://wirenboard.com/wiki/index.php/Движок_правил_wb-rules
в разделе “Создание однотипных правил”.

Обертка (closure) в общем случае выглядит так:
(function() {
// код
})();

Ну, вот ссылка для почитать:
https://www.w3schools.com/js/js_function_closures.asp


#13

вот чуть более подробно с кусочками кода.

// spalna
  { devname: "vhome_48932/1", name: null, target: "spalna svet" },
  { devname: "vhome_48932/2", name: "spalna mid", target: function() { TurnLight( false ); } },
  { devname: "vhome_48932/3", name: null, target: "balkon svet" },
  // vhod
  { devname: "vhome_29476/1", name: "radio vhod 1", target: allOn },
  { devname: "vhome_29476/2", name: null, target: "koridor svet vhod" },
  { devname: "vhome_29476/3", name: "radio vhod 3", target: allOff },
  
for( var rc = 0; rc < mySources.length; rc++ )
{
  var re = mySources[rc];
 if( re.target )
  {
    if( typeof re.target == "function" )
    {
      defineRule( "targetrule" + rc, {
        whenChanged: re.devname,
        then: 
        (function( devname, target ) {
          var first_run = true;
          return function( newValue, devName, cellName ) {
            if( first_run ) { first_run = false; return; }
            log( "on " + devname + " call " + target + "nv={} dn={} cn={}", newValue, devName, cellName );
            target( newValue, devName, cellName );
          };
        })( re.devname, re.target )
      });	
    }
    else
    {
     defineRule( "targetrule" + rc, {
        whenChanged: re.devname,
        then:
        (function( devname, target, devtarget ) {
          var first_run = true;
		  return function( newValue, devName, cellName ) {
            if( first_run ) { first_run = false; return; }
			log( "on '" + devname + "' change '" + target + "' (" + devtarget + ")" + "nv={} dn={} cn={}", newValue, devName, cellName );
			dev[devtarget] = ! dev[devtarget];
          };
        })( re.devname, re.target, getTarget( re.target ) )
      });	
    }
  }
}

#14

у меня, например, срабатывает whenChanged на вирт. устройстве, пока что одном. Никаких retained я не задавал. Срабатывает при рестарте правил. Почему оно вообще срабатывает? Можно, конечно, завалить таймаутом обработки, но это что, нормальная работа? У меня этот вирт. девайс срабатывает только по внешней команде, если ему 1 кинут, а после обработки это правило само сбрасывает значение 1 на 0. Это mosquitto глючит при вкл. правил? Проясните, пожалуйста. Конечно, грабли-костыли это хорошо, но еще лучше, когда понимаешь принцип работы.


#15

Можно этот пример?


#16

не знаю, даже, что это даст, но вот скрипт:

defineVirtualDevice(“GetCurrentStates”,
{
title: “GetCurrentStates”,
cells:
{
get:
{
type: “switch”,
value: false
},
data:
{
type: “text”,
value: “”
},
Current:
{
type: “text”,
value: “1”
}
}
});

defineRule(“send current states”,
{
whenChanged: “GetCurrentStates/get”,
then: function (newValue, devName, cellName)
{
if (newValue == 1)
{
log(“GetCurrentStates: правило отработало, сбрасываем значение в 0”);

  dev["GetCurrentStates"]["Current"] = "12345qwert";
  dev["GetCurrentStates"]["get"] = 0;
}  

}
});

вот строка в бридж

topic /devices/GetCurrentStates/controls/get/on both 2 “” /client/AFDB3MCD
topic /devices/GetCurrentStates/controls/Current both 2 “” /client/AFDB3MCD

при рестарте правил москито вываливает состояние аналоговых выходов 0-10В и этот вирт девайс - 12345qwert


#17

причем это делает москито. Я поменял в скрипте содержание, сохранил, правила рестартанул, а при рестарте все-равно шли старые значения. А когда я через морду принудительно дал команду, данные обновились и стали теперь при рестарте приходить новые. Как будто москито их запоминает, как-то выделяет и шлет при рестарте… Как это уже задолбало, то одно, то другое. День уходит на простую функцию…
Может, есть другой брокер, не знаете?
Так что, наверное, вопрос к whenChanged снимается, это не его рук дело… Ну а толку то, что снимается, система в итоге работает криво через одно место.


#18

Действительно, непонятная логика брокера.
При перезагрузке правила повторять отправку retained-значений, а не того, что установлено в defineRules в качестве инициализирующего.
Не хватает функции обновления этих retained-значений из обновленного правила (например, если смысл перезагрузки его был как раз связан с установкой нового инициализирующего значения).


#19

Добрый день! Есть такая проблема, предполагаем внести изменения в новом движке правил (по срокам сориентировать не могу). Вот цитата из https://wirenboard.com/wiki/index.php/Движок_правил_wb-rules_2.0:

В предыдущих версиях wb-rules значения контролов виртуальных устройств хранились только в MQTT retained, что не очень надёжно (в случае
потери питания данные могли быть легко утеряны). Начиная с версии 2.0, эти значения сохраняются также в специальное хранилище в постоянной
памяти и восстанавливаются при загрузке сценария.

Если необходимо каждый раз при перезагрузке скрипта восстанавливать строго определённое значение (т.е. не восстанавливать предыдущее сохранённое),
можно добавить в описание контрола поле forceDefault:

defineVirtualDevice("vdev", {
    ...
    cells: {
        ...
        mycell: {
            type: "value",
            value: "10",
            forceDefault: true // при каждой загрузке сценария поле mycell будет получать значение 10
        }
    }
});

По умолчанию поле принимает значение false.


#20

Разве этих изменений нет в текущей 1.7.* версии? По-моему уже есть…