Сценарии - новая версия API
-
@Alex_Jet У меня управление одним устройством с разных сценариев) я думал о глобальных переменных, чтобы там хранить значение свойства, но при выполнении сценария его придется каждый раз перепроверять. Думал может есть простой способ обращения)
-
@homa, ну а какая разница? Это же не искать какое-то определенное значение в раздутой БД! Все довольно просто и быстро).
А вообще интересная задача - управление одним устройством разными сценариями...я не могу придумать никакого практического применения(((. Просвятите что вы хотите сделать!
У меня единственный навороченный сценарий/немного поверх другого - это отключение авто-режима актюатора если вдруг кто-то открыл окно для проветривания, например. Правда после открытия окна проверяется - включен ли актюатор (то есть холодно и помещение уже греется), если да то просто выходим, если нет, то отключаем у него авто режим))) При этом если в комнате стало холоднее уставки "эконом", то возвращаем актюатору авто-режим (чтобы отопление принудительно включилось).
-
@Alex_Jet у меня скорее просто неоптимальная реализация для управления мотором)
у меня есть три актуатора = 3 положения кнопки вытяжки, три сенсора = три положения физического переключателя. один сценарий синхронизирует состояния физики и логики, второй делает правильное переключение, чтобы не включить две "кнопки" сразу, а третий регулирует скорость в зависимости от разницы температур и электропотребления
-
@homa, как-то все сложно. А не проще сделать переключатель? У меня рекуператор (3 скорости) управляется переключателем (выключен, авто, скорость 1, скорость 2, скорость 3). Есть 2 сценария - один "чувствует" переключение переключателя и отрабатывает нужные действия, другой - активируется только когда переключатель в состоянии "Авто".
А!!! Еще не пойму - зачем нужен физический переключатель? У нас же умный дом! Я конечно тоже установил двухклавишный переключатель (висит на MegaD и MegaD управляет рекуператором, причем 3 выхода MegaD связаны в sw link чтобы всегда включалось одно из трех реле), но это для экстренного режима управления рекуператором (включить/выключить рекуператор, выбрать скорость 1 или 2) когда все сдохло/умер сервер/смартфон/роутер/коммутатор и т.п.
-
@Alex_Jet Физические переключатели всегда должны дублировать основной функционал. А если переделываешь что-то совсем аналоговое, то приходится привязываться к старым органам управления
-
есть сценарий, при включении света по датчику движения, дополнил: если включаю дополнительный свет чтобы свет тот что загорелся по датчику движения погас, но что то не работает, где исправить ошибку?
/** * @name Світло коридор 1 поверх * @desc Включает светильник по датчику движения, отключает при отсутствии движения в течение заданного времени. * @version 4 */ const lamp = Device("ActorD", "Светильник", [ {"name":"timeOff", "note":"Светильник горит без движения, сек", "type":"number", "val":5}, {"name":"light_threshold", "note":"Порог освещенности для включения", "type":"number", "val":20} ]); const lamp2 = Device("ActorD", "Освітлення Led коридор 1 поверх Коридор"); const motion = Device("SensorD", "Датчик движения"); const lightSensor = Device("SensorA", "Датчик освещенности (аналоговый)"); // Запустим сценарий при сработке датчика движения, если светильник не горит и освещенность ниже порога // ИЛИ если движение прекратилось, а светильник горит startOnChange([motion,lamp2], motion.isOn() && lamp.isOff() && lightSensor.value <= lamp.getParam("light_threshold") || motion.isOff() && lamp.isOn()); script ({ start() { if(lamp2.isOff()){ this.addTimer("T1"); if (motion.isOn()) { lamp.on(); } else { // движения нет - взводим таймер, чтобы отключить this.startTimer("T1", lamp.getParam("timeOff"), "turnOff"); } // В любом случае следим за датчиком движения и светильником this.addListener(motion, "onMotion"); this.addListener(lamp, "onLamp"); }else{ lamp.off(); this.exit(); } }, onMotion() { // Если движение прекратилось - взводим таймер if (motion.isOff() && this.timer.T1 == "off") { this.startTimer("T1", lamp.getParam("timeOff"), "turnOff"); } // Если движение возобновилось - сбрасываем таймер if (motion.isOn()) { this.stopTimer('T1'); } }, onLamp() { // Светильник выключили другим способом - выходим if (lamp.isOff()) this.exit(); }, // Функция, которая сработает, когда таймер досчитает (нет движения в течение заданного // времени) - отключаем и выходим turnOff() { lamp.off(); this.exit(); } });
-
@homa, не согласен - по мне физика отмирает. Даже в современных авто уже нет физических кнопок. Кстати, у моего рекуператора есть свой контроллер с дисплеем и т.д., но я его просто выкинул, подключив все к MegaD.
Тренд в управлении - автоматика, мобильные приложения и голосовые ассистенты. Тот же рекуператор у меня всегда в режиме авто, "ручные" режимы сделаны скорее для того чтобы были.
-
Участник @homa написал
И следом вопрос корректно ли объявлять одно и тоже свойство для одного и того же устройства в разных сценариях, или есть какие-то другие варианты обращения к ранее объявленным свойствам
идея в том, чтобы изменять из разных сценариев одно свойство... выходит не выходит)
Почему не выходит? Без проблем можно обращаться к одному свойству устройства из нескольких сценариев. При этом достаточно объявить свойство в одном сценарии, в других можно и не объявлять. При объявлении это свойство создается на уровне устройства. Проблема отсутствия свойства может быть только при первом запуске и после перезагрузки.
-
Добрый день! А можно добавить возможность писать значение устройства из плагина не в value, а в созданный в скрипте дополнительный параметр?
чтобы в value писать уже значение после обработки
-
подскажите пожалуйста решение задачи. требуется присвоить значение виртуальному счетчику от физического
по простому продублировать значение одного другому
-
@m_n61rus Сделайте сценарий
/** * @name xx * @desc * @version 4 */ const meter6 = Device("METER6"); //оригинал const meter7 = Device("METER7"); //копия startOnChange(meter6); script({ start() { this.assign(meter7, 'aval', meter6.value); } });
-
@homa спасибо попробую
-
@intrapro, расскажите как сделать скрипт, который можно запустить кнопкой и остановить. При этом запущенный скрипт должен работать в бесконечном цикле. Задача - работа гирлянды на базе WS2818 с включением вручную, по расписанию, по датчикам.
Пример скрипта на php для бесконечной работы гирлянды:$cmd_list = array("FF0000", "00FF00", "0000FF", "FFFFFF", "000000"); $color = 0; while(true) { $cmd = ""; for ( $i = 0; $i < 9; $i++ ) { $color = dechex(rand(0,100)); if ( strlen($color) == 1 ) $color = "0".$color; $cmd .= $color; } file_get_contents("http://192.168.0.14/sec/?pt=35&ws=$cmd"); sleep(1); }
-
@Alex_Jet
Примерно так.Если нужно 4 состояния ленты менять по кругу бесконечно, то скрипт такой.
По нажатию кнопки включаете ленту в состояние 1, запускаете таймер с переходом на "stage2", запускаете слушателя кнопки c переходом на "turnOff".
stage2 - переключаете ленту в состояние 2, запускаете таймер с переходом на "stage3"
stage3 - переключаете ленту в состояние 3, запускаете таймер с переходом на "stage4"
stage4 - переключаете ленту в состояние 4, запускаете таймер с переходом на "stage5"
stage5 - переключаете ленту в состояние 1, запускаете таймер с переходом на "stage2"
turnOff - останавливаете таймер, выходите из скрипта.Если нужно не по кнопке, а из другого скрипта, сделайте актуатор, состояние которого меняете из другого скрипта или той же кнопкой, а скрипт ленты запускайте по изменению этого актуатора, и слушатель в нем на изменения этого актуатора, а не кнопки.
-
@Alex_Jet, Добрый день! @Erik прав - нужен актуатор, который можно переключать как угодно - интерактивно, сценарием, по расписанию...
Сценарий гирлянды запускается при включении этого актуатора.
Состояния в php скрипте меняются случайным образом, поэтому логика еще проще:
- Добавить слушателя для актуатора-триггера
- Генерировать строку цветов случайным образом
- Передать команду на MegaD
- Взвести таймер 1 сек
По таймеру - повторить пункты 1-3
При выключении триггера - завершить сценарий
-
Участник @intrapro написал в Сценарии - новая версия API:
@Alex_Jet, Добрый день! @Erik прав - нужен актуатор, который можно переключать как угодно - интерактивно, сценарием, по расписанию...
Сценарий гирлянды запускается при включении этого актуатора.
Состояния в php скрипте меняются случайным образом, поэтому логика еще проще:
- Добавить слушателя для актуатора-триггера
- Генерировать строку цветов случайным образом
- Передать команду на MegaD
- Взвести таймер 1 сек
По таймеру - повторить пункты 1-3
При выключении триггера - завершить сценарийСпасибо за помощь. В принципе получилось примерно что хотел. Надо еще подумать как сделать более плавное и быстрое изменение уровня одного и того же цвета (главное не зациклить цикл... иначе iH перестанет откликаться), но в принципе все работоспособно! Для тех кто еще не юзал RGB ленты, подключенные к MegaD, через iH:
/** * @name Освещение - гирлянда из WS2818 * @desc Имитация работы гирлянды * @version 4 */ const sw = Device("ACTORA_GARLAND1_01"); startOnChange(sw); script({ plugin: "megad1", //Переменная названия плагина channel: 34, //Переменная номера канала плагина cmd: '000000', //Переменная команды chip: 151, //Количество чипов в ленте WS2818 num: 3, i: 0, start() { this.ChangeStateSw(); }, ChangeStateSw() { //Остановка таймера для выхода из "цикла" this.stopTimer("T1"); switch(sw.value) { case 0: this.cmd = '000000'; break; case 1: this.cmd = '00FF00'; break; case 2: this.cmd = 'FF0000'; break; case 3: this.cmd = '0000FF'; break; case 4: this.ChangeRed(); break; case 5: this.ChangeGreen(); break; case 6: this.ChangeBlue(); break; case 7: this.RandomColor(); break; case 8: this.num = 3; this.RandomPlay(); break; case 9: this.num = 6; this.RandomPlay(); break; case 10: this.num = 9; this.RandomPlay(); break; } if(sw.value < 4) { this.SendDataToWS2818(this.plugin, this.channel, this.cmd, this.chip); this.cmd = ''; this.exit(); } }, ChangeRed() { this.addListener(sw, "ChangeStateSw"); let color = this.i.toString(16); if(color.length == 1) color = '0' +color; this.cmd = '00' +color+ '00'; this.SendDataToWS2818(this.plugin, this.channel, this.cmd, this.chip); this.cmd = ''; if(this.i >= 0 && this.i < 16) this.i += 1; else if(this.i >= 16 && this.i < 96) this.i += 8; else if(this.i >= 96 && this.i < 240) this.i += 16; else if(this.i >= 240) this.i = 0; this.startTimer("T1", 1, "ChangeRed"); }, ChangeGreen() { this.addListener(sw, "ChangeStateSw"); let color = this.i.toString(16); if(color.length == 1) color = '0' +color; this.cmd = color+ '0000'; this.SendDataToWS2818(this.plugin, this.channel, this.cmd, this.chip); this.cmd = ''; if(this.i >= 0 && this.i < 16) this.i += 1; else if(this.i >= 16 && this.i < 96) this.i += 8; else if(this.i >= 96 && this.i < 240) this.i += 16; else if(this.i >= 240) this.i = 0; this.startTimer("T1", 1, "ChangeGreen"); }, ChangeBlue() { this.addListener(sw, "ChangeStateSw"); let color = this.i.toString(16); if(color.length == 1) color = '0' +color; this.cmd = '0000' +color; this.SendDataToWS2818(this.plugin, this.channel, this.cmd, this.chip); this.cmd = ''; if(this.i >= 0 && this.i < 16) this.i += 1; else if(this.i >= 16 && this.i < 96) this.i += 8; else if(this.i >= 96 && this.i < 240) this.i += 16; else if(this.i >= 240) this.i = 0; this.startTimer("T1", 1, "ChangeBlue"); }, RandomColor() { this.addListener(sw, "ChangeStateSw"); let color = ["FF0000", "00FF00", "0000FF", "FFFFFF", "000000"]; this.cmd = color[this.GetRandomInt(0, 5)] + color[this.GetRandomInt(0, 5)] + color[this.GetRandomInt(0, 5)]; this.SendDataToWS2818(this.plugin, this.channel, this.cmd, this.chip); this.cmd = ''; this.startTimer("T1", 1, "RandomColor"); }, RandomPlay() { this.addListener(sw, "ChangeStateSw"); let color; for (let i = 0; i < this.num; i++ ) { color = this.GetRandomInt(0,256).toString(16); if(color.length == 1) color = '0' +color; this.cmd += color; } this.SendDataToWS2818(this.plugin, this.channel, this.cmd, this.chip); this.cmd = ''; this.startTimer("T1", 1, "RandomPlay"); }, //Функция возвращает случайное целое число между min (включительно) и max (не включая max) GetRandomInt(min, max) { return Math.floor( Math.random() * (max - min)) + min; }, //Функция формирования данных для ленты WS2818 SendDataToWS2818(plugin, channel, cmd, chip) { this.pluginCommand({unit: plugin, command: '/sec/?pt=' +channel+ '&ws=' +cmd+ '&chip=' +chip}); } });
Управление лентой - с помощью аналогового актюатора, который имеет слайдер с диапазоном 1-10. Чтобы управлять по расписанию нужен сценарий, в который из расписания будем передавать параметр, а этот параметр будет присваиваться значению актюатора.
-
Добрый день! Можно ли использовать в мультисценариях помимо переменный устройств, постоянные? Делаю так:
В ошибке вижу:
Или все таки нужно добавлять это устройство ко всем в списке?
-
Участник @homa написал в Сценарии - новая версия API:
Добрый день! Можно ли использовать в мультисценариях помимо переменный устройств, постоянные? Делаю так:
Добрый день, нет, поле все равно будет доступно для выбора, даже если вы пропишите id, но ошибки не должно быть
-
Добрый день!
Сейчас движок сценариев распознает тип - обычный сценарий или мульти, анализируя именно описание устройств.
За счет этого легко можно превратить обычный сценарий в мультисценарий и обратно. Поэтому смешивать параметрические и реальные устройства в текущей версии не получится
-
Добрый день, есть проблема, передаю на одну megad одновременно два запроса, как сделать между запросами паузу. если я на одну мегу одновременно даю 2 запроса this.pluginCommand не обрабатывает 2 запрос.
/** * @name Новый мультисценарий * @desc * @version 4 */ const switch_1 = Device("ActorE","Switch"); const jalusi = Device("ActorD","Actor",[ {"name":"point_open", "note":"Пін відкриття", "type":"number", "val":15}, {"name":"point_close", "note":"Пін закриття", "type":"number", "val":16} ]); startOnChange([switch_1,jalusi]); script({ start() { if(this.isChanged(switch_1)){ this.onSwitch(); } if(this.isChanged(jalusi)){ this.onJalusi(); } }, onSwitch(){ switch(switch_1.value){ case 0: jalusi.on(); if(jalusi.id === "ACTOR7"){ this.pluginCommand({unit:'megad3', command:'/258/?cmd='+jalusi.getParam('point_open')+':1;p200;'+jalusi.getParam('point_open')+':0'}); } if(jalusi.id === "ACTOR8"){ //this.pluginCommand({unit:'megad2', command:'/258/?cmd='+jalusi.getParam('point_open')+':1;p210;'+jalusi.getParam('point_open')+':0'}); } if(jalusi.id === "ACTOR9"){ //this.pluginCommand({unit:'megad2', command:'/258/?cmd='+jalusi.getParam('point_open')+':1;p230;'+jalusi.getParam('point_open')+':0'}); } break; case 1: //this.pluginCommand({unit:'megad3', command:'/258/?cmd='+jalusi.getParam('point_open')+':0;'+jalusi.getParam('point_close')+':0'}); break; case 2: jalusi.off(); if(jalusi.id === "ACTOR7"){ this.pluginCommand({unit:'megad3', command:'/258/?cmd='+jalusi.getParam('point_close')+':1;p200;'+jalusi.getParam('point_close')+':0'}); } if(jalusi.id === "ACTOR8"){ this.pluginCommand({unit:'megad2', command:'/258/?cmd='+jalusi.getParam('point_close')+':1;p210;'+jalusi.getParam('point_close')+':0'}); } if(jalusi.id === "ACTOR9"){ this.pluginCommand({unit:'megad2', command:'/258/?cmd='+jalusi.getParam('point_close')+':1;p230;'+jalusi.getParam('point_close')+':0'}); } break; } this.log('Жалюзі статус : '+switch_1.value+' '+jalusi.id); }, onJalusi(){ //this.log(this.isChanged(jalusi)+' 38 line'); if(jalusi.isOn()){ //this.log('jalusi On'); if(jalusi.id === "ACTOR7"){ this.pluginCommand({unit:'megad3', command:'/258/?cmd='+jalusi.getParam('point_open')+':1;p200;'+jalusi.getParam('point_open')+':0'}); } if(jalusi.id === "ACTOR8"){ this.pluginCommand({unit:'megad2', command:'/258/?cmd='+jalusi.getParam('point_open')+':1;p210;'+jalusi.getParam('point_open')+':0'}); } if(jalusi.id === "ACTOR9"){ this.pluginCommand({unit:'megad2', command:'/258/?cmd='+jalusi.getParam('point_open')+':1;p230;'+jalusi.getParam('point_open')+':0'}); } }else{ //this.log('jalusi Off'); if(jalusi.id === "ACTOR7"){ this.pluginCommand({unit:'megad3', command:'/258/?cmd='+jalusi.getParam('point_close')+':1;p200;'+jalusi.getParam('point_close')+':0'}); } if(jalusi.id === "ACTOR8"){ this.pluginCommand({unit:'megad2', command:'/258/?cmd='+jalusi.getParam('point_close')+':1;p210;'+jalusi.getParam('point_close')+':0'}); } if(jalusi.id === "ACTOR9"){ this.pluginCommand({unit:'megad2', command:'/258/?cmd='+jalusi.getParam('point_close')+':1;p230;'+jalusi.getParam('point_close')+':0'}); } } this.exit(); } });