EVENT_TAG_CHANGE
Добрый день!
Использую сервер для вызова сценария "Выключить все". Пользуюсь обработчиком 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;
}
});
}
Customer support service by UserEcho
Добрый день.
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)
получает значения, которые приходят в имеющиеся фидбэки Иридиум сервера и выполняет действие (в данном случае выводит в лог). Если серверный фидбэк удалён, но в драйвере фидбэк остался, то значение не придёт в сервер. Если новое значение равно предыдущему, то EVENT_TAG_CHANGE в IR.GetServer не сработает. Так сделано умышленно, но в справке это не отражено. В документацию мы внесём дополнение. Спасибо, что обратили внимание на это.{
IR.Log(name + ": " + value);
});
Можно вместо 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 предназначен для виртуальных фидбэков и токенов проекта.
Да. С тэгами драйвера работает
У вас есть ещё вопросы по вашему обращению?
Нет. Можно закрыть тему
Рады помочь.
прошу резюмировать: я правильно понял, что работа листенера 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 должен хорошо знать, - однако этой информации не нашел.
Вывод: так делать нельзя, но для этого нужно знать. Переменная в модбасе не менялась, но выполнился дважды вызов функции.
Решение: Подписываемся на переменные с задержкой - зависит от шины: модбас секунды, Knx - минуты. Тогда запуск сервера проходит без изменений по этой переменной и не будет ложных tag change.
Тот же эксперимент, но с битовой переменной на модбасе.
Результат - при запуске сервера global tag change получает сначала 1, потом 0, если был 0 в переменной. ВСЕГДА сначала проходит 1. Если сеттаймаутом не убрать это значение - будет ошибка!
Добрый день.
Мы поняли о чём речь и сейчас исследуем ваш вопрос. Ноль действительно приходит в драйвер при старте Иридиум сервера, даже если нет реального подключения к оборудованию. Происходит это один раз и только в начале работы сервера. Предварительно можем отметить, что так работает Script Modifier в драйверах. Пока в качестве временной меры рекомендуем по возможности не использовать значение 0 в проекте либо делать задержку, как Александр указал ранее.
Добрый день.
Работа Script Modifier в версии 1.3.3 скорректирована. Теперь в фидбэки не приходит 0 во время старта при отсутствии доступа к реальному оборудованию.