0
Will be answered

EVENT_TAG_CHANGE

Евгений Лешкив 2 months ago • updated by Vladimir Ovchinnikov 1 month ago 32

Добрый день!

Использую сервер для вызова сценария "Выключить все". Пользуюсь обработчиком EVENT_TAG_CHANGE. Данный обработчик реагирует только на изменение тэга. Для данной задачи изменение тэга не происходит, т.к. глобальная сцена всегда вызывается одним значением. В итоге приходится следом, после выполнения скрипта, досылать "некое" значение, чтобы обеспечить изменение переменной.

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

//===================================================

function Scenes()   //определение функции
{
   IR.AddListener(IR.EVENT_TAG_CHANGE, IR.GetServer(), function(name, value)
   { 
      //IR.Log("Имя переменной = " + name + "; Значение = " + value); //В лог выводим имя тега и новое значение
      switch(name)
      {
         case "BAOS.Сцены пом_1":
            if(value == 0)
            {
               IR.SetVariable("Server.Channels.BAOS.sw 1_1 - люстры",0);
               IR.SetVariable("Server.Channels.BAOS.sw 1_2 - бра",0);
               //===
               IR.SetVariable("Server.Channels.BAOS.Сцены пом_1",30);
            }
           break;
      }
   });
}

GOOD, I'M SATISFIED
Satisfaction mark by Евгений Лешкив 2 months ago
Under review

Добрый день.

1) Как вызываете глобальную сцену? Отправляете команду в нативный драйвер?

2) Если значения фидбэков вам не нужны, то значение чего хотите получить в серверном проекте?

1.1 var Scenes_1 = new Scenes();

1.2 Да. Драйвер KNX

2.1 Фидбэки, как раз, нужны, поэтому меня не устраиват то, что я вынужден обновлять значение фидбэка "левым" значением

2.2 Хочу, чтобы скрипт отрабатывал не только изменение, но и получение одного и того же значения переменной

Почему бы тогда не использовать GetFeedback для получения текущего значения из нужных фидбэков?

Слушатель с EVENT_TAG_CHANGE лучше объявить вне функции и по изменению тэга выполнять нужные действия (отправить команду в нативный драйвер, изменить значение виртуального фидбэка и т. д.). EVENT_TAG_CHANGE реагирует на любое новое значение, даже если новое равно предыдущему.

"реагирует на любое новое значение, даже если новое равно предыдущему" - это не так. Даже, если реагирует, то действий не выполняет

GetFeedback должен выполняться событийно или по таймеру, а это усложняет скрипт. Хочется универсальное решение, работающее в фоне

Только что проверили ещё раз. Конструкция:

IR.AddListener(IR.EVENT_TAG_CHANGE, IR.GetServer(), function(name, value)
{  
IR.Log(name + ": " + value);
});

получает значения, которые приходят в имеющиеся фидбэки Иридиум сервера и выполняет действие (в данном случае выводит в лог). Если серверный фидбэк удалён, но в драйвере фидбэк остался, то значение не придёт в сервер. Если новое значение равно предыдущему, то EVENT_TAG_CHANGE в IR.GetServer не сработает. Так сделано умышленно, но в справке это не отражено. В документацию мы внесём дополнение. Спасибо, что обратили внимание на это.


Можно вместо IR.GetServer использовать IR.GetDevice, но только для отдельных драйверов. В таком случае, если новое значение равно предыдущему, то EVENT_TAG_CHANGE сработает.

Я так понял, что единственный выход для меня это:

//===============================

var Scenes_1 = new Scenes("Сцены пом_1");

function Scenes(sceneName)   //определение функции
{
   var sceneNumber;
  
   function Control()
   {
      sceneNumber = IR.GetVariable("Server.Tags.BAOS." + sceneName);
      switch(sceneNumber)
      {
         case 0:
            IR.SetVariable("Server.Channels.BAOS.sw 1_1 - люстры",0);
            IR.SetVariable("Server.Channels.BAOS.sw 1_2 - бра",0);
           break;
         case 1:
            IR.SetVariable("Server.Channels.BAOS.sw 1_1 - люстры",0);
            IR.SetVariable("Server.Channels.BAOS.sw 1_2 - бра",0);
            break;
      }
   }
  
   IR.SetInterval(1000, Control);
}

//===============================

Мне в такой конструкции не нравится, что она забирает ресурсы процессора постоянно, а не событийно. Или нет?

Ерунда получается. В этом случае я не могу узнать, что новые данные получены, если они не изменились. И получается, что в цикле постоянно отправляются данные.

Подскажите решение. Нужно определить событие, что данные в канал обратной связи получены, пусть даже значение не изменилось.

Добрый день.

Если вы хотите отслеживать все получения данных, даже если новые значения совпадают со старыми, то используйте IR.GetDevice(). Примерно так:

IR.AddListener(IR.EVENT_TAG_CHANGE, IR.GetDevice("Modbus TCP"), function(name, value)
{  
IR.Log(name + ": " + value);
});


Для нативных драйверов нужно использовать Set, т. е. отправлять команду в драйвер. SetVariable предназначен для виртуальных фидбэков и токенов проекта.

Да. С тэгами драйвера работает

У вас есть ещё вопросы по вашему обращению?

Нет. Можно закрыть тему

Answered

Рады помочь.

прошу резюмировать: я правильно понял,  что работа листенера IR.EVENT_TAG_CHANGE отличается в зависимости от того на что подписаны?

до этого я имел информацию, что только Global_Tag_Change реагирует на новые значения, а для Event мы даже писали код с запоминаем прошлого значения. оказывается надо было на сервер подписываться?

Добрый день, Александр.

Да. К сожалению, в документации этот момент был упущен, но сейчас уже добавили информацию.

По существу:


1) EVENT_TAG_CHANGE реагирует на новое получение данных, даже если новое значение совпадает с уже имеющимся. Это справедливо, если используется IR.GetDevice(). Пример:

IR.AddListener(IR.EVENT_TAG_CHANGE, IR.GetDevice("Modbus TCP"), function(name, value)
{  
IR.Log(name + ": " + value);
});


2) EVENT_TAG_CHANGE не реагирует на получение новых данных, если новое значение совпадает с уже имеющимся. Это справедливо, если используется IR.GetServer(). Пример:

IR.AddListener(IR.EVENT_TAG_CHANGE, IR.GetServer(), function(name, value) {   IR.Log(name + ": " + value); });

Если новое значение не совпадает с уже имеющимся, то EVENT_TAG_CHANGE срабатывает.


3) EVENT_GLOBAL_TAG_CHANGE реагирует только на изменение и не сработает, если новое значение равно предыдущему.


IR.GetServer() охватывает все фидбэки во всех драйверах Иридиум сервера, но реагирует только на изменения. В этом EVENT_TAG_CHANGE совместно с IR.GetServer похож на EVENT_GLOBAL_TAG_CHANGE.

IR.GetDevice() работает только в пределах конкретного драйвера, но реагирует на любое новое значение. Даже, если новое равно предыдущему.

Именно так.

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

Да, драйвер работает с оборудованием, а IR.GetDevice() с сервером.

это очень важное дополнение, комуто может  быть и так понятно с начала, но не мне. теперь яснее стало

В документации отразили.

тогда вопрос встречный - если мы слушаем драйвер, а не сервер, то value в листенере будет до применения модификаторов?

Вы имеете в виду функции, которые могут использоваться в Script Modifier? Сначала приходит value, а потом выполняется модификация. Проверить реальное значение можно через GetFeedback. Модификатор это уже постобработка.

нет, вопрос немного другой:

IR.AddListener(IR.EVENT_TAG_CHANGE, IR.GetDevice("Modbus TCP"), function(name, value) 
{  
IR.Log(name + ": " + value);
});


value в логе будет до модификации или после? судя по всему до модификатора.


а в варианте:

IR.AddListener(IR.EVENT_TAG_CHANGE, IR.GetServer(), function(name, value) {   IR.Log(name + ": " + value); });


Value в логе  будет уже модифицированным?





В обоих случаях value будет до модификации.

тогда вообще непонятно, в листенере до модификации, а в переменых, которые на кнопки приклеены - уже модифицированы. где этот неуловимый момент модификации?

Слушатель через EVENT_TAG_CHANGE в IR.GetDevice() читает новые значения в фидбэках. Эти значения приходят "как есть". Что драйвер отдал, то мы и читаем. Точно так же и в IR.GetServer(). Никакой модификации на в IR.GetDevice(), ни в IR.GetServer() не происходит.

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

Например, нам нужно увеличить значение в 10 раз. В этом случае пишем функцию, которая умножает value на 10 и возвращает результат. Функцию указываем в Script Modifier. Функция получает в качестве аргумента value "как есть", модифицирует его и возвращает новое значение. Новое значение можно вывести в лог, записать в виртуальный фидбэк, вывести на кнопку в панельном проекте и т. д. Если у вас панельный проект, без серверного, то модификация возможна через шаблоны.

Т. е. неизменное value первично, а модифицированное вторично. Для того, чтоб модифицировать, нужно сперва получить что-то. Это "что-то" есть value из EVENT_TAG_CHANGE.

брррр... непоняток стало больше - не вижу логики пока. 

у нас есть feedback по KNX драйверу Outside light value. на него стоит модификатор "умножить на 10". 

по каналу приходит значение 100. Что и в каком случае мы получим? Рассматриваем только серверный проект. 

по вашему утверждению любой листенер передает value "сырое", до модификатора, так?

IR.AddListener(IR.EVENT_TAG_CHANGE, IR.GetDevice("KNX IP Router"), function(name, value) 
{  
IR.Log(name + ": " + value);    //100 - (* спорно, думаю здесь модифицированное значение 1000 должно быть*)
});

а если мы считаем feedback:

IR.GetVariable("Server.Tags.KNX IP Router.Outside light value");  - это tag сервера, он ДОЛЖЕН быть обработан модификатором. те значение 1000

IR.GetVariable("Drivers.KNX IP Router.Tags.Outside light value"); - а здесь я так понимаю драйверный feedback, он не обработан модификатором, те значение 100

ведь модификатор указан на серверном теге. сервер должен "увидеть" его уже модифицированным 

я так думаю. прав - неправ?

Добрый день.


Если используется функция в Script Modifier, то после её выполнения получаем новое значение. Скрипту требуется время и пока он не завершил обработку - значение в фидбэке будет "как есть". Хотя для наблюдателя выполнение происходит практически мгновенно, - это и есть тот "неуловимый момент модификации". Александр, вы про момент спрашивали, поэтому объясняем. Использовать неизменное значение в таком случае не выйдет. Причина: функция в Script Modifier.


При использовании модифицирующей функции (того, что указано в Script Modifier) получаем только новое значение. Если сделать GetFeedback - получим новое значение. Если вам нужно неизменное значение, которое пришло в драйвер, то уберите функцию из Script Modifier.

в продолжение к  IR.EVENT_GLOBAL_TAG_CHANGE

постановка задачи: по битовой переменной vare1 из модбас драйвера надо выполнить функцию1, если сменилось значение с 0 на 1 или выполнить функцию2 если сменилось значение с 1 на 0. 

Решение:

запускаем EVENT_GLOBAL_TAG_CHANGE  с вызовом соответствующих функций, подписываемся на переменную 
IR.SubscribeTagChange("Drivers.KNX IP Router.var1");

В модбасе переменная равна 0 и не меняется. 

Заливаем проект на сервер, сервер перезапускается с новым проектом.

видим в логах, что подписались на переменную var1, далее листенер получает по модбасу 0 в эту переменную и вызывает функцию 2, которая сейчас не должна выполняться - ничего ведь в модбасе нее менялось. 

видимо переменная инициализировалась как undefined и получила значение ноль из модбаса, и считает, что это изменение переменной. Так? 


как этого избежать?   ибо функция 2 может натворить дел нехороших, если невовремя вызвать ее

Буквально вчера столкнулся с этой же проблемой.

В алгоритм завязаны котел, вентустановка и охранная сигнализация.

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

Все работает по EVENT_TAG_CHANGE драйвера KNX на борту UMC сервера.

Система стоит на охране - значение переменной в шине, отвечающей за это = 1.

При перезапуске сервер опрашивает переменные. В какой-то момент в его памяти эта переменная инициализируется как = 0. В этот момент он переводит все системы в нормальный режим.

у меня такая же конфигурация, только охрана на контроллер другой завязана и опрос по модбасу. 

Евгений, наберите мне пож - 89257721776, вопрос у меня по UMC

Добрый день.

Александр, драйвер Modbus опрашивает ПЛК с установленной периодичностью. В вашем случае, если по опросу пришёл 0, то выполнится функция2. Если нужно выполнять функцию только при изменении с 1 на 0, то скриптом:

1) Сохраняйте текущее значение.

2) Сравнивайте сохранённой с полученным.

3) Если полученное не равно сохранённому, то сохраняйте новое и выполняйте нужную функцию.

Добрый день, 

вы пишите правильные вещи. Но немного не о том. Здесь ключевое слово - ПЕРЕЗАГРУЗКА. Программа на js прекрасно ведет себя в продолжительной работе, но что происходит при перезаливке проекта или перезагрузке по питанию?


я провел несколько тестов и вот что выяснил - довольно неожиданные вещи, которые любой инсталлятор iRidi должен хорошо знать, - однако этой информации не нашел. 

  1. дано - модбас дрв:  переменная HR со значением 55. 
  2. к тагу на сервере прикручиваем модификатор "*0,1"
  3. делаем global tag change
  4. подписываемся на 2 переменных на tag в сервере и на tag в modbus дрв
  5. заливаем проект. 
  6. получаем в логах: первое - по каналу сервера приходит ноль обязательно ( а значение у нас в модбасе 55). ЭТО ОЧЕНЬ ВАЖНЫЙ МОМЕНТ! выполняется все что должно выполниться по значению переменной 0. ОШИБКА!!!
  7. приходит значение по каналу сервера 5,5 ( - сработал модификатор. если без модификатора, то пришло бы 55) - тоже изменение. Сработает и по этому значению. ТОЖЕ ОШИБКА!
  8. приходит значение по каналу модбам дрв - 55. тут все ок логично, вопросов нет. круто сделано

Вывод: так делать нельзя, но для этого нужно знать. Переменная в модбасе не менялась, но  выполнился дважды вызов функции.

Решение: Подписываемся на переменные с задержкой - зависит от шины: модбас секунды, Knx  - минуты. Тогда запуск сервера проходит без изменений по этой переменной и не будет ложных tag change.


Тот же эксперимент, но с битовой переменной на модбасе. 

Результат - при запуске сервера global tag change получает сначала 1, потом 0, если был 0 в переменной. ВСЕГДА сначала проходит 1. Если сеттаймаутом не убрать это значение - будет ошибка!

Will be answered

Добрый день.

Мы поняли о чём речь и сейчас исследуем ваш вопрос. Ноль действительно приходит в драйвер при старте Иридиум сервера, даже если нет реального подключения к оборудованию. Происходит это один раз и только в начале работы сервера. Предварительно можем отметить, что так работает Script Modifier в драйверах. Пока в качестве временной меры рекомендуем по возможности не использовать значение 0 в проекте либо делать задержку, как Александр указал ранее.