Сценарии - новая версия API
-
Добрый день!
Написал сценарий для тестирования выгоды перехода на трехтарифный расчет электроэнергии:
> /** > * @name ThreeTarif > * @desc > * @version 4 > */ > > const T1 = Device("METER18"); > const T2 = Device("METER17"); > const T3 = Device("METER19"); > const mmr = Device("METER20"); > const day = Device("METER6"); > const night = Device("METER5"); > const pulse3t = Device("SENSOR2"); > > startOnChange(pulse3t); > > script({ > Weight:0.0002, // вес импульса > T1r:4.9, //свет T1 > T2r:1.6, //свет T2 > T3r:3.77, //свет T3 > start() { > const dt = new Date(); > mmrbf = (t1.value-t1.getParam('uptoMonth'))*t1r+(t2.value-t2.getParam('uptoMonth'))*t2r+(t3.value-t3.getParam('uptoMonth'))*t3r; > mmrbf.toFixed(2) > this.assign(mmr, 'aval', mmrbf); > //eesum.toFixed(2) > //cwsum = (metercwv.value + metercwt.value - metercwv.getParam('uptoMonth') - metercwt.getParam('uptoMonth'))*this.cw > if (dt.getHours() < 7 || dt.getHours()>=23) { // c 23:00 - 7:00 ночной тариф T2 > this.assign(T2, 'aval', T2.value+this.Weight); > return false; > } > if (dt.getHours() >= 7 || dt.getHours()<10) { // c 7:00 - 10:00 тариф T1 > this.assign(T1, 'aval', T1.value+this.Weight); > } > if (dt.getHours() >= 10 || dt.getHours()<17) { // c 10:00 - 17:00 тариф T3 > this.assign(T3, 'aval', T3.value+this.Weight); > return false; > } > if (dt.getHours() >= 17 || dt.getHours()<21) { // c 17:00 - 21:00 тариф T1 > this.assign(T1, 'aval', T1.value+this.Weight); > return false; > } > if (dt.getHours() >= 21 || dt.getHours()<23) { // c 21:00 - 23:00 тариф T3 > this.assign(T3, 'aval', T3.value+this.Weight); > return false; > } > > > > } > }); >
Но он почему-то не срабатывает, отладчик пустой как будто не отрабатывает триггер "startOnChange(pulse3t)" хотя в соседнем сценарии по этому триггеру все работает
PS разобрался, к числовым константам нужно обращаться как this.t1r
-
Подскажите по расписанию мультисценарий отработает по всем группам устройств?
Кстати, обратил внимание, что если меняешь "Название" сценария, то его имя в Расписаниях остается старое. Вероятно поменяется только после перезагрузки iH?
-
Добрый день!
Есть простейшее расписание - включить на закате две лампочки, но включается только одна. Причем включается та, которая будет первой в списке)) Пересоздать задачу не помогает, но в журнале отображается запись "Команда on Расписание"
Спасибо. Проверим, пофиксим
-
Подскажите по расписанию мультисценарий отработает по всем группам устройств?
Нет, в списке же вы выбираете конкретный экземпляр сценария, в скобках набор устройств.
Кстати, обратил внимание, что если меняешь "Название" сценария, то его имя в Расписаниях остается старое. Вероятно поменяется только после перезагрузки iH?
Да, после перезагрузки конечно поменяется. Проверим, постараемся исправить
-
@denis-000:
Доброго времени суток. Пытаюсь изучить сценарии графические и у меня вопрос. Руководствуясь документацией, я маленько запутался ( фото прилагаю ) там указано, что " От датчика температуры (STEMP_1_1) поступает значение (VALUE) и сравнивается с уставкой (SETPOINT). Если температура меньше уставки, включаем батарею отопления (RADIATOR_1_1). Если больше, выключаем.
Все работает. Температура в комнате регулируется " непонятно то, с чем сравнивается, если там не указана константа, а указано заданное значение ( setpoint ). Если смотреть эту картинку, откуда берется это заданное значение, как его задать?
Отсюда: (см.скрин)
В свойствах устройства должна стоять галка "есть уставка". Задать значение можно длительным нажатием на элемент
-
Здравствуйте.
Решаю следующую задачу.
Кнопки меняют значение виртуального актуатора.
По факту изменения значения этого виртуального актуатора запускается скрипт, который присваивает измененное значение реальному актуатору, и тот передает значение по модбас физическуму устройству.
При быстрых нажатиях простой скрипт терял последнее нажатие, и значение виртуального актуатора менялось, а реальному не присваивалось.
Добавил таймеры.
Задумка - записывать измененное значение в реальный актуатор спустя 2 сек. При этом, повторное нажатие кнопки до истечения срока останавливает таймер, и запускает его снова.
Думаю, что такая конструкция должна один раз записать последнее значение, когда пользователь уже отнажимается и поутихнет.
Но ничего никуда не пишется.
Пенял на одинарные ковычки. Те, которые указаны в описании стстема отвергла (не дала исполняемую функцию в this.startTimer('T1', 2.0, 'ActComf.setValue(newvalue)'); взять в те ковычни, которые у вас на сайте указаны).
Поменял на другие - тоже нет результата.
И без ковычек не работает
const ActRz = Device("ActorA", "Режим отопления"); const ActComf = Device("ActorA", "Уставка Комфорт"); const ActDsp = Device("ActorA", "Отображение уставки текущего режима"); startOnChange(ActDsp); script({ start() { this.addTimer(T1); if (ActRz.value === 0) { let newvalue = ActDsp.value; this.stopTimer('T1'); this.startTimer('T1', 2.0, 'ActComf.setValue(newvalue)'); return; } } });
Что у меня не так?
И так не работает
start() { this.addTimer(T1); if (ActRz.value === 0) { let newvalue = ActDsp.value; if (this.timer.T1 == on) this.stopTimer.T1; this.startTimer(T1, 2.0, ActComf.setValue(newvalue)); return; }
-
Кажется нашел
script ({ start() { lamp.on(); this.log('Hello, World!'); this.startTimer('T1', 10, 'next'); // Обратите внимание, здесь мы не определяем callback напрямую, // а просто сообщаем движку имя метода, который нужно будет запустить }, next() { lamp.off(); } });
-
const ActRz = Device("ActorA", "Режим отопления"); const ActComf = Device("ActorA", "Уставка Комфорт"); const ActDsp = Device("ActorA", "Отображение уставки текущего режима"); startOnChange(ActDsp); script({ start() { this.addTimer(T1); if (ActRz.value === 0) { let newvalue = ActDsp.value; this.stopTimer('T1'); this.startTimer('T1', 2.0, 'next'); return; } }, next() { ActComf.setValue(newvalue); } });
не работает.
-
> const ActRz = Device("ActorA", "Режим отопления"); > const ActComf = Device("ActorA", "Уставка Комфорт"); > const ActDsp = Device("ActorA", "Отображение уставки текущего режима"); > > startOnChange(ActDsp); > > script({ > start() { > this.addTimer(T1); > if (ActRz.value === 0) { > let newvalue = ActDsp.value; > this.stopTimer('T1'); > this.startTimer('T1', 2.0, 'next'); > return; > } > }, > next() { > ActComf.setValue(newvalue); > } > }); >
не работает.
Добрый день!
Здесь есть синтаксическая ошибка (объявление newvalue) и структурная
Попробуйте написать так, чуть позже прокомментирую:
const ActRz = Device("ActorA", "Режим отопления"); const ActComf = Device("ActorA", "Уставка Комфорт"); const ActDsp = Device("ActorA", "Отображение уставки текущего режима"); startOnChange(ActDsp); script({ newvalue:0, start() { if (ActRz.value === 0) { // Не совсем понятно, что это. Но надо, так надо this.newvalue = ActDsp.value; this.log('start value ' + this.newvalue) this.startTimer('T1', 2, 'next'); this.addListener(ActDsp, 'resetTimer'); } }, next() { this.log('SET '+this.newvalue) ActComf.setValue(this.newvalue); this.exit(); }, resetTimer() { if (this.newvalue != ActDsp.value) { this.newvalue = ActDsp.value; this.log('new value '+this.newvalue) this.stopTimer('T1'); this.startTimer('T1', 2, 'next'); } } });
this.log вставлен, чтобы отследить работу алгоритма в отладчике или журнале
-
"Не совсем понятно …" - эта часть скрипта должна выполняться, если режим отопления комфортный (ActRz.value = 0)
Полная версия для 3-х разных режимов присваивает значения разным актуаторам.
А в 4-и режиме ничего не присваивает.
const ActRz = Device("ActorA", "Режим отопления"); const ActComf = Device("ActorA", "Уставка Комфорт"); const ActEco = Device("ActorA", "Уставка Эконом"); const ActOff = Device("ActorA", "Уставка Выключено"); const ActDsp = Device("ActorA", "Отображение уставки текущего режима"); startOnChange(ActDsp); script({ newvalue:0, start() { if (ActRz.value === 0) { // Не совсем понятно, что это. Но надо, так надо this.newvalue = ActDsp.value; this.log('start value ' + this.newvalue) this.startTimer('T1', 2, 'next1'); this.addListener(ActDsp, 'resetTimer'); } if (ActRz.value == 1) { // Не совсем понятно, что это. Но надо, так надо this.newvalue = ActDsp.value; this.log('start value ' + this.newvalue) this.startTimer('T1', 2, 'next2'); this.addListener(ActDsp, 'resetTimer'); } if (ActRz.value == 3) { // Не совсем понятно, что это. Но надо, так надо this.newvalue = ActDsp.value; this.log('start value ' + this.newvalue) this.startTimer('T1', 2, 'next3'); this.addListener(ActDsp, 'resetTimer'); } }, next1() { this.log('SET '+this.newvalue) ActComf.setValue(this.newvalue); this.exit(); }, next2() { this.log('SET '+this.newvalue) ActEco.setValue(this.newvalue); this.exit(); }, next3() { this.log('SET '+this.newvalue) ActOff.setValue(this.newvalue); this.exit(); }, resetTimer() { if (this.newvalue != ActDsp.value) { this.newvalue = ActDsp.value; this.log('new value '+this.newvalue) this.stopTimer('T1'); this.startTimer('T1', 2, 'next'); } } });
А что будет, если второе нажатие случится ДО истечения таймера от первого нажатия? Таймер сам перезапускается, ему команды старт/стоп давать не нужно?
-
Этот скрипт (без таймеров) у меня работает
const ActRz = Device("ActorA", "Режим отопления"); const ActComf = Device("ActorA", "Уставка Комфорт"); const ActEco = Device("ActorA", "Уставка Эконом"); const ActOff = Device("ActorA", "Уставка Выключено"); const ActDsp = Device("ActorA", "Отображение уставки текущего режима"); startOnChange(ActDsp); script({ start() { if (ActRz.value === 0) { let newvalue = ActDsp.value; ActComf.setValue(newvalue); return; } if (ActRz.value == 1) { let newvalue = ActDsp.value; ActEco.setValue(newvalue); return; } if (ActRz.value == 3) { let newvalue = ActDsp.value; ActOff.setValue(newvalue); return; } } });
Если добавляю таймер только в экономичный режим, все работает (в экономичном режиме переключает тоже)
const ActRz = Device("ActorA", "Режим отопления"); const ActComf = Device("ActorA", "Уставка Комфорт"); const ActEco = Device("ActorA", "Уставка Эконом"); const ActOff = Device("ActorA", "Уставка Выключено"); const ActDsp = Device("ActorA", "Отображение уставки текущего режима"); startOnChange(ActDsp); script({ newvalue:0, start() { if (ActRz.value === 0) { let newvalue = ActDsp.value; ActComf.setValue(newvalue); return; } if (ActRz.value == 1) { this.newvalue = ActDsp.value; this.log('start value ' + this.newvalue) this.startTimer('T1', 2, 'next'); this.addListener(ActDsp, 'resetTimer'); } if (ActRz.value == 3) { let newvalue = ActDsp.value; ActOff.setValue(newvalue); return; } }, next() { this.log('SET '+this.newvalue) ActEco.setValue(this.newvalue); this.exit(); }, resetTimer() { if (this.newvalue != ActDsp.value) { this.newvalue = ActDsp.value; this.log('new value '+this.newvalue) this.stopTimer('T1'); this.startTimer('T1', 2, 'next'); } } });
А если по аналогии делаю все режимы - ничего не работает
const ActRz = Device("ActorA", "Режим отопления"); const ActComf = Device("ActorA", "Уставка Комфорт"); const ActEco = Device("ActorA", "Уставка Эконом"); const ActOff = Device("ActorA", "Уставка Выключено"); const ActDsp = Device("ActorA", "Отображение уставки текущего режима"); startOnChange(ActDsp); script({ newvalue:0, start() { if (ActRz.value === 0) { this.log('start value ' + this.newvalue) this.startTimer('T1', 2, 'next1'); this.addListener(ActDsp, 'resetTimer'); } if (ActRz.value == 1) { this.newvalue = ActDsp.value; this.log('start value ' + this.newvalue) this.startTimer('T1', 2, 'next2'); this.addListener(ActDsp, 'resetTimer'); } if (ActRz.value == 3) { this.log('start value ' + this.newvalue) this.startTimer('T1', 2, 'next3'); this.addListener(ActDsp, 'resetTimer'); } }, next1() { this.log('SET '+this.newvalue) ActComf.setValue(this.newvalue); this.exit(); }, next2() { this.log('SET '+this.newvalue) ActEco.setValue(this.newvalue); this.exit(); }, next3() { this.log('SET '+this.newvalue) ActOff.setValue(this.newvalue); this.exit(); }, resetTimer() { if (this.newvalue != ActDsp.value) { this.newvalue = ActDsp.value; this.log('new value '+this.newvalue) this.stopTimer('T1'); this.startTimer('T1', 2, 'next'); } } });
-
А что будет, если второе нажатие случится ДО истечения таймера от первого нажатия? Таймер сам перезапускается, ему команды старт/стоп давать не нужно?
Для этого добавлен слушатель : this.addListener(ActDsp, 'resetTimer');
В целом, механизм такой:
Если сценарий запустился и взвел таймеры, он второй раз по триггерам не запустится. Он ведь уже работает!
И если нужно следить за событиями устройств изнутри сценария, нужно добавить слушателя
this.addListener(ActDsp, 'resetTimer');
Слушатель срабатывает по событиям устройства ActDsp, то есть при втором … n-ном нажатии. По событию выполнится resetTimer
В нем смотрим - изменилось значение - тогда перевзводим таймер
Если же таймер досчитал и обновил значение - нужно завершить сценарий
this.exit();.
Тогда следующее нажатие уже пройдет через старт.
Если сценарий со слушателем не завершить - он останется активным
-
Этот скрипт (без таймеров) у меня работает
А если по аналогии делаю все режимы - ничего не работает
Вы значение this.newvalue присваиваете только в одном из IF.
if (ActRz.value === 0) { // ЗДЕСЬ НЕТ this.log('start value ' + this.newvalue) this.startTimer('T1', 2, 'next1'); this.addListener(ActDsp, 'resetTimer'); } if (ActRz.value == 1) { this.newvalue = ActDsp.value; this.log('start value ' + this.newvalue) this.startTimer('T1', 2, 'next2'); this.addListener(ActDsp, 'resetTimer'); } if (ActRz.value == 3) { // ЗДЕСЬ НЕТ this.log('start value ' + this.newvalue) this.startTimer('T1', 2, 'next3'); this.addListener(ActDsp, 'resetTimer'); } }
Можно вынести в начало
start() { this.newvalue = ActDsp.value; if (ActRz.value === 0) { ...
-
Заработало так
const ActRz = Device("ActorA", "Режим отопления"); const ActComf = Device("ActorA", "Уставка Комфорт"); const ActEco = Device("ActorA", "Уставка Эконом"); const ActOff = Device("ActorA", "Уставка Выключено"); const ActDsp = Device("ActorA", "Отображение уставки текущего режима"); startOnChange(ActDsp); script({ newvalue:0, start() { if (ActRz.value === 0) { this.newvalue = ActDsp.value; this.startTimer('T1', 2, 'next1'); this.addListener(ActDsp, 'resetTimer1'); } if (ActRz.value == 1) { this.newvalue = ActDsp.value; this.startTimer('T2', 2, 'next2'); this.addListener(ActDsp, 'resetTimer2'); } if (ActRz.value == 3) { this.newvalue = ActDsp.value; this.startTimer('T3', 2, 'next3'); this.addListener(ActDsp, 'resetTimer3'); } }, next1() { this.log('SET '+this.newvalue) ActComf.setValue(this.newvalue); this.exit(); }, next2() { this.log('SET '+this.newvalue) ActEco.setValue(this.newvalue); this.exit(); }, next3() { this.log('SET '+this.newvalue) ActOff.setValue(this.newvalue); this.exit(); }, resetTimer1() { if (this.newvalue != ActDsp.value) { this.newvalue = ActDsp.value; this.log('new value '+this.newvalue) this.stopTimer('T1'); this.startTimer('T1', 2, 'next1'); } }, resetTimer2() { if (this.newvalue != ActDsp.value) { this.newvalue = ActDsp.value; this.log('new value '+this.newvalue) this.stopTimer('T2'); this.startTimer('T2', 2, 'next2'); } }, resetTimer3() { if (this.newvalue != ActDsp.value) { this.newvalue = ActDsp.value; this.log('new value '+this.newvalue) this.stopTimer('T3'); this.startTimer('T3', 2, 'next3'); } } });
Посоветуйте учебник.
Хаотические манипуляции с непонятным текстом интересны только первые 20 минут
-
Заработало так
Посоветуйте учебник.
Хаотические манипуляции с непонятным текстом интересны только первые 20 минут
Вы оказывается и таймеры разные взводили Но получилось же :!:
Можно значительно короче - один и тот же таймер и один resetTimer - за один раз сработает только один вариант
По учебнику - любой по JavaScript, основы, можно в комбинации: JavaScript+Node.js, серверный JavaScript
Нужно еще привыкнуть, что сценарии выполняются не напрямую, а движком сценариев IH
И все происходит не линейно, а асинхронно
Здесь описан механизм сценариев с примерами: https://ih-systems.com/ru/about-scenes/
Но Вы вроде это уже смотрели. В принципе, если понять, как работает ваш сценарий, то задача можно сказать решена
В нем используются все основные концепции
И советую применять отладчик в рабочих сценариях, там виден ход выполнения
Вот результат выполнения одного из вариантов вашего скрипта
06.02 16:50:53.228 S9(ACTORA1,,ACTORA2,ACTORA3) Trigger ACTORA3 06.02 16:50:53.229 S9(ACTORA1,,ACTORA2,ACTORA3) Started 06.02 16:50:53.230 S9(ACTORA1,,ACTORA2,ACTORA3) log: start value 28 06.02 16:50:53.357 S9(ACTORA1,,ACTORA2,ACTORA3) start timer T1 for 2 sek 06.02 16:50:55.795 S9(ACTORA1,,ACTORA2,ACTORA3) listener on event ACTORA3: resetTimer 06.02 16:50:55.796 S9(ACTORA1,,ACTORA2,ACTORA3) exec function resetTimer 06.02 16:50:55.797 S9(ACTORA1,,ACTORA2,ACTORA3) log: new value 35 06.02 16:50:55.818 S9(ACTORA1,,ACTORA2,ACTORA3) stop timer T1 06.02 16:50:55.819 S9(ACTORA1,,ACTORA2,ACTORA3) start timer T1 for 2 sek 06.02 16:51:00.872 S9(ACTORA1,,ACTORA2,ACTORA3) Done timer T1 06.02 16:51:00.873 S9(ACTORA1,,ACTORA2,ACTORA3) exec function next 06.02 16:51:00.874 S9(ACTORA1,,ACTORA2,ACTORA3) log: SET 35 06.02 16:51:00.895 S9(ACTORA1,,ACTORA2,ACTORA3) do ACTORA2 set 35 06.02 16:51:00.897 S9(ACTORA1,,ACTORA2,ACTORA3) exit
-
Пока все по углам не развел - не работало.
-
Подскажите, а сейчас есть возможность в сценариях сделать что-то такое:
act.on(onResponse:[this.flag = 1])
То есть нужно при подтверждении включении актюатора установить какой-нибудь флаг, чтобы по нему произвести другие действия.
Конечно можно взвести таймер и проверить включился ли актюатор (act.isOn()), но это будет плохим решением когда одна железка отрабатывает за несколько мс (виртуальный актюатор, не подключенный к каналам), другой за 1-2 секунды (MegaD с дисплеями особенно), третий за 30-180 секунд (приводы заслонок с обратной связью).
-
Подскажите, а сейчас есть возможность в сценариях сделать что-то такое:
> act.on(onResponse:[this.flag = 1]) >
То есть нужно при подтверждении включении актюатора установить какой-нибудь флаг, чтобы по нему произвести другие действия.
Конечно можно взвести таймер и проверить включился ли актюатор (act.isOn()), но это будет плохим решением когда одна железка отрабатывает за несколько мс (виртуальный актюатор, не подключенный к каналам), другой за 1-2 секунды (MegaD с дисплеями особенно), третий за 30-180 секунд (приводы заслонок с обратной связью).
Можно, конечно
Нужно установить слушателя событий this.addListener(device, 'funname')
Пример 4 из документации https://ih-systems.com/ru/about-scenes/
/** * @name Hello World and Blinking and Manual * @desc Тестовый сценарий * @version 4 */ const lamp = Device("LAMP1"); script ({ lampState:0, // Просто добавляем объекту свойства - переменные count:0, // Внутри методов обращаться к ним нужно через this start() { this.count = 0; // В таких переменных данные сохраняются и между запусками. // Иногда это нужно, в данном случае считаем с нуля this.lampState = lamp.value; // фиксируем, в каком состоянии находится лампа // при запуске this.log('Hello, World!'); this.addListener(lamp, 'onLamp'); // Слушаем переключения состояния лампы this.next(); // Запускаем функцию, которая также будет работать по таймеру }, next() { if (this.lampState) { this.lampState = 0; // Здесь ставим ожидаемое состояние lamp.off(); // Даем команду на выключение. // В следующей строке лампа возможно еще не выключится, // если мы работаем с физическим устр-вом // Когда выключится и пришлет новое состояние - зависит от железа // и от плагина. При переключении сработает onLamp if (this.count <= 10) { this.startTimer('T1', 0.4, 'next'); } else { // Выходим после выключения, 10 раз уже мигнули this.exit(); } } else { this.lampState = 1; lamp.on(); this.count += 1; // считаем включения this.startTimer('T1', 3, 'next'); } }, onLamp() { if (this.lampState != lamp.value) { // Было внешнее переключение - завершим сценарий this.exit(); } } });
-
А можно без слушателя и таймеров.
Запускать сценарий по факту любого изменения актуатора ( startOnChange(Act); ).
А внутри сценария проверять какое значение от принял, перепроверять (получать подтверждения), и присваивать/изменять значение глобальной переменной.
-
Можно значительно короче - один и тот же таймер и один resetTimer - за один раз сработает только один вариант
Там каждый "nextХ" работает с конкретным актуатором, а каждый "resetX" отсылает к конкретному "nextX".
Чтобы их оставить по одному, необходжтмо "нексту" строковой переменной имя нужного актуатора передавать.
Это как сделать?