Сценарии - новая версия API



  • @amgstone, у Вас просто не верное решение используется - вы передаете полную команду с сервера на MegaD. Но MegaD конечно это отрабатывает, правда есть оговорки по этому поводу. Однако сам сервер iH может выдержать любую паузу! Поэтому стоит сделать так:

    //В основном цикле
    this.pluginCommand({unit:'megad3', command:'/258/?cmd='+jalusi.getParam('point_open')+':1'});
    this.startTimer("T1", 0.200, "Stop_Jalusi");
    
    //Функция остановки жалузи
    Stop_Jalusi() {
     this.pluginCommand({ unit:"megad3", command:{url:"/258/?cmd=" +jalusi.getParam('point_open')+":0", onResponse:[{id:"jalusi.getParam('point_open')",value:"OFF"}]} });
     this.exit();
    }
    

    onResponse - это как раз callback сработки канала (когда на команду контроллер отвечает Done), в данном случае - MegaD. Не особо понимаю что за дополнительный параметр у Вас - jalusi.getParam('point_open'), но в данном случае именно он примет значение OFF принудительно когда канал MegaD будет выключен.

    Вообще для включения/выключения устройств я в некоторых сценариях применяю такую связку:

    //Включаем устройство, если оно выключено и ждем изменение его состояния
    if(this.device.isOff()) { this.device.on(); this.addListener(this.device, 'Function') }
    
    //Эта функция запускается когда произошло изменение состояния устройства
    Function() {
        //Тут что-то делаем
        this.exit(); //Принудительно выходим из сценария чтобы завершились слушатели
    }
    


  • @Alex_Jet спасибо, сегодня попробую а то эти ролокасети это предпоследний минингит.



  • подскажите как можно сделать очередь отправки команд на MegaD, не могу добится чтобы на одной меге отрабатывали сразу 2 команды, посылаю 2 команды 1 останавливается а 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:
                if(jalusi.id === "ACTOR7"){
                  this.pluginCommand({unit:'megad3', command:'/258/?cmd='+jalusi.getParam('point_open')+':1' });
                  this.startTimer("T1", 20, "Stop_Jalusi_up");
                }
                if(jalusi.id === "ACTOR8"){
                  this.pluginCommand({unit:'megad2', command:'/258/?cmd='+jalusi.getParam('point_open')+':1'});
                  this.startTimer("T1", 40, "Stop_Jalusi_up");
                }
                if(jalusi.id === "ACTOR9"){
                  this.pluginCommand({unit:'megad2', command:'/258/?cmd='+jalusi.getParam('point_open')+':1'});
                  this.startTimer("T1", 60, "Stop_Jalusi_up");
                }
              break;
              case 1:
                
              break;
              case 2:
                if(jalusi.id === "ACTOR7"){
                  this.pluginCommand({unit:'megad3', command:'/258/?cmd='+jalusi.getParam('point_close')+':1'});
                  this.startTimer("T1", 20, "Stop_Jalusi_down");
                }
                if(jalusi.id === "ACTOR8"){
                  this.pluginCommand({unit:'megad2', command:'/258/?cmd='+jalusi.getParam('point_close')+':1'});
                  this.startTimer("T1", 40, "Stop_Jalusi_down");
                }
                if(jalusi.id === "ACTOR9"){
                  this.pluginCommand({unit:'megad2', command:'/258/?cmd='+jalusi.getParam('point_close')+':1'});
                  this.startTimer("T1", 60, "Stop_Jalusi_down");
                }
              break;
            }
            this.log('Жалюзі статус : '+switch_1.value+' '+jalusi.id);
        },
        onJalusi(){
          if(jalusi.isOn()){
            if(jalusi.id === "ACTOR7"){
              this.pluginCommand({unit:'megad3', command:'/258/?cmd='+jalusi.getParam('point_open')+':1'});
              this.startTimer("T1", 20, "Stop_Jalusi_up");
            }
            if(jalusi.id === "ACTOR8"){
              this.pluginCommand({unit:'megad2', command:'/258/?cmd='+jalusi.getParam('point_open')+':1'});
              this.startTimer("T1", 40, "Stop_Jalusi_up");
            }
            if(jalusi.id === "ACTOR9"){
              this.pluginCommand({unit:'megad2', command:'/258/?cmd='+jalusi.getParam('point_open')+':1'});
              this.startTimer("T1", 60, "Stop_Jalusi_up");
            }
          }else{
            if(jalusi.id === "ACTOR7"){
              this.pluginCommand({unit:'megad3', command:'/258/?cmd='+jalusi.getParam('point_close')+':1'});
              this.startTimer("T1", 20, "Stop_Jalusi_down");
            }
            if(jalusi.id === "ACTOR8"){
              this.pluginCommand({unit:'megad2', command:'/258/?cmd='+jalusi.getParam('point_close')+':1'});
              this.startTimer("T1", 40, "Stop_Jalusi_down");
            }
            if(jalusi.id === "ACTOR9"){
              this.pluginCommand({unit:'megad2', command:'/258/?cmd='+jalusi.getParam('point_close')+':1'});
              this.startTimer("T1", 60, "Stop_Jalusi_down");
            }
          }
        },
        Stop_Jalusi_up() {
            if(jalusi.id === "ACTOR7"){
              this.pluginCommand({unit:'megad3', command:'/258/?cmd='+jalusi.getParam('point_open')+':0', onResponse:[{id:"jalusi.getParam('point_open')",value:"ON"}]});
            }
            if(jalusi.id === "ACTOR8"){
              this.pluginCommand({unit:'megad2', command:'/258/?cmd='+jalusi.getParam('point_open')+':0', onResponse:[{id:"jalusi.getParam('point_open')",value:"ON"}]});
            }
            if(jalusi.id === "ACTOR9"){
              this.pluginCommand({unit:'megad2', command:'/258/?cmd='+jalusi.getParam('point_open')+':0', onResponse:[{id:"jalusi.getParam('point_open')",value:"ON"}]});
            }
        },
        Stop_Jalusi_down() {
            if(jalusi.id === "ACTOR7"){
              this.pluginCommand({unit:'megad3', command:'/258/?cmd='+jalusi.getParam('point_close')+':0', onResponse:[{id:"jalusi.getParam('point_close')",value:"OFF"}]});
            }
            if(jalusi.id === "ACTOR8"){
              this.pluginCommand({unit:'megad2', command:'/258/?cmd='+jalusi.getParam('point_close')+':0', onResponse:[{id:"jalusi.getParam('point_close')",value:"OFF"}]});
            }
            if(jalusi.id === "ACTOR9"){
              this.pluginCommand({unit:'megad2', command:'/258/?cmd='+jalusi.getParam('point_close')+':0', onResponse:[{id:"jalusi.getParam('point_close')",value:"OFF"}]});
            }
          }
    });
    
    


  • @amgstone, очередь отправки команд на контроллер формирует плагин, команды отправляются последовательно по мере поступления. У Вас не работает управление двумя одновременно?
    Посмотрите, что происходит в отладчике плагина.



  • Если кому будет интересно сценарий для роллет:

    /** 
    * @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)){
            if(switch_1.value===1){
              this.onJalusi();
            }
          }
        },
        onSwitch(){
          switch(switch_1.value){
              case 0:
                if(jalusi.isOff()){
                  if(global.get('jalusi_work')){
                    global.set('jalusi_count',global.get('jalusi_count')+1);
                    this.log('Жалюзі статус : jalusi_count : '+global.get('jalusi_count'));
                    this.startTimer("T1"+global.get('jalusi_count'), global.get('jalusi_time'), "Start_Jalusi_up");
                    global.set('jalusi_time',(global.get('jalusi_time')+28));
                  }else{
                    global.set('jalusi_work',true);
                    this.log('Жалюзі статус : '+jalusi.id);
                    global.set('jalusi_count',1);
                    global.set('jalusi_time',28);
                    this.startTimer("T11", 0.100, "Start_Jalusi_up");
                  }
                }
              break;
              case 1:
                  global.remove('jalusi_work');
                  global.remove('jalusi_count');
              break;
              case 2:
                if(jalusi.isOn()){
                  if(global.get('jalusi_work')){
                    global.set('jalusi_count',global.get('jalusi_count')+1);
                    this.log('Жалюзі статус : jalusi_count : '+global.get('jalusi_count'));
                    this.startTimer("T1"+global.get('jalusi_count'), global.get('jalusi_time'), "Start_Jalusi_down");
                    global.set('jalusi_time',(global.get('jalusi_time')+28));
                  }else{
                    global.set('jalusi_work',true);
                    this.log('Жалюзі статус : '+jalusi.id);
                    global.set('jalusi_count',1);
                    global.set('jalusi_time',28);
                    this.startTimer("T11", 0.100, "Start_Jalusi_down");
                  }
                }
              break;
            }
        },
        onJalusi(){
          if(switch_1.value===1){
            if(jalusi.isOn()){
              if(global.get('jalusi_work')){
                global.set('jalusi_count',global.get('jalusi_count')+1);
                this.log('Жалюзі статус : jalusi_count : '+global.get('jalusi_count'));
                this.startTimer("T1"+global.get('jalusi_count'), global.get('jalusi_time'), "Start_Jalusi_up");
                global.set('jalusi_time',(global.get('jalusi_time')+28));
              }else{
                global.set('jalusi_work',true);
                this.log('Жалюзі статус : '+jalusi.id);
                global.set('jalusi_count',1);
                global.set('jalusi_time',28);
                this.startTimer("T11", 0.100, "Start_Jalusi_up");
              }
            }else{
              if(global.get('jalusi_work')){
                global.set('jalusi_count',global.get('jalusi_count')+1);
                this.log('Жалюзі статус : jalusi_count : '+global.get('jalusi_count'));
                this.startTimer("T1"+global.get('jalusi_count'), global.get('jalusi_time'), "Start_Jalusi_down");
                global.set('jalusi_time',(global.get('jalusi_time')+28));
              }else{
                global.set('jalusi_work',true);
                this.log('Жалюзі статус : '+jalusi.id);
                global.set('jalusi_count',1);
                global.set('jalusi_time',28);
                this.startTimer("T11", 0.100, "Start_Jalusi_down");
              }
            }
          }
        },
        Start_Jalusi_up(){
          jalusi.on();
          this.log('Жалюзі статус : Start_Jalusi_up '+jalusi.id);
          switch(jalusi.id){
            case "ACTOR7":
              this.pluginCommand({unit:'megad3', command:'/258/?cmd='+jalusi.getParam('point_open')+':1;'});
            break;
            case "ACTOR8":
              this.pluginCommand({unit:'megad2', command:'/258/?cmd='+jalusi.getParam('point_open')+':1;'});
            break;
            case "ACTOR9":
              this.pluginCommand({unit:'megad2', command:'/258/?cmd='+jalusi.getParam('point_open')+':1;'});
            break;
          }
          this.startTimer("T2", 25, "Stop_Jalusi_up");
        },
        Start_Jalusi_down(){
          jalusi.off();
          this.log('Жалюзі статус : Start_Jalusi_down '+jalusi.id);
          switch(jalusi.id){
            case "ACTOR7":
              this.pluginCommand({unit:'megad3', command:'/258/?cmd='+jalusi.getParam('point_close')+':1;'});
            break;
            case "ACTOR8":
              this.pluginCommand({unit:'megad2', command:'/258/?cmd='+jalusi.getParam('point_close')+':1;'});
            break;
            case "ACTOR9":
              this.pluginCommand({unit:'megad2', command:'/258/?cmd='+jalusi.getParam('point_close')+':1;'});
            break;
          }
          this.startTimer("T2", 25, "Stop_Jalusi_down");
        },
        Stop_Jalusi_up() {
          global.set('jalusi_count',global.get('jalusi_count')-1);
          this.log('Жалюзі статус : Stop_Jalusi_up '+jalusi.id+' jalusi_count : '+global.get('jalusi_count'));
          switch(jalusi.id){
            case "ACTOR7":
              this.pluginCommand({unit:'megad3', command:'/258/?cmd='+jalusi.getParam('point_open')+':0;'});
            break;
            case "ACTOR8":
              this.pluginCommand({unit:'megad2', command:'/258/?cmd='+jalusi.getParam('point_open')+':0;'});
            break;
            case "ACTOR9":
              this.pluginCommand({unit:'megad2', command:'/258/?cmd='+jalusi.getParam('point_open')+':0;'});
            break;
          }
          global.set('jalusi_work',false);
          
          if(global.get('jalusi_count')===0){
            switch_1.setValue(1);
          }
          this.log('End Jalusi Up');
        },
        Stop_Jalusi_down() {
          global.set('jalusi_count',global.get('jalusi_count')-1);
          this.log('Жалюзі статус : Stop_Jalusi_down '+jalusi.id+' jalusi_count : '+global.get('jalusi_count'));
          switch(jalusi.id){
            case "ACTOR7":
              this.pluginCommand({unit:'megad3', command:'/258/?cmd='+jalusi.getParam('point_close')+':0;'});
            break;
            case "ACTOR8":
              this.pluginCommand({unit:'megad2', command:'/258/?cmd='+jalusi.getParam('point_close')+':0;'});
            break;
            case "ACTOR9":
              this.pluginCommand({unit:'megad2', command:'/258/?cmd='+jalusi.getParam('point_close')+':0;'});
            break;
          }
          global.set('jalusi_work',false);
          
          if(global.get('jalusi_count')===0){
            switch_1.setValue(1);
          }
          this.log('End Jalusi Down');
        }
    });
    


  • можно в блок схеме передать значение?

    start() {
          mid.setValue([10011, 20]); // id 0 - 8, 10 - 13, 20 - 29, custom 10001 | vol 0 - standart, 10 - 100
        } 
    });
    


  • Подскажите как в блок схеме (http://joxi.ru/1A5JM43SDpdwbr) добавить возможность чтобы рас в сутку срабатывал вентилятор на определенное время даже если влажность не достигла заданой.



  • @amgstone
    Отдельный скрипт и запуск его по расписанию.



  • Коллеги, переписываю сценарии под версию 4. И чтобы не сломать систему отопления) подскажите как правильно присваивать уставки температурным датчикам?

    Сейчас это делается так - this.assign(dt, "defval", dt.nightTemp);
    Сейчас нужно сделать вероятно dt.setpoint(dt.nightTemp)??? Или, скорее всего даже вот так: dt.setpoint( dt.getParam("ecoTemp") )???



  • @Alex_Jet
    Совершенно верно, параметры в сценарии напрямую не доступны, нужно использовать getParam("имя параметра") / setParam("имя параметра", значение).

    Просто dt.setpoint - это значение уставки. Для уставки есть специальная команда setSetpoint (да, довольно коряво 😞 )
    Другой вариант - любое свойство можно присвоить с помощью setParam.
    Таким образом, есть два варианта:

    dt.setSetpoint( dt.getParam("nightTemp") )
    

    или

    dt.setParam( "setpoint", dt.getParam("nightTemp") )
    


  • Коллеги, у меня почему-то в связке с "Актуатор аналоговый универсальный" не работает слушатель..., точнее сценарий зависает. Имею такой код:

          if(this.device.isOff()) {
            this.device.on();
            this.addListener(this.device, 'TTStoVTdevOn');
          }
    

    В отладчике - вижу включение актуатора и все...после этого надо скрипт либо пересохранить, либо принудительно остановить. С "Актуатор дискретный универсальный" все работает как надо!
    Если строчку this.addListener(this.device, 'TTStoVTdevOn'); закомментировать, то все работает.

    Идея состояла в том, что как только актуатор изменит свое состояние (включится), то сообщать об этом пользователю.



  • @Alex_Jet, покажите весь сценарий. Или хотя бы функции start и TTStoVTdevOn.
    И что за устройство this.device? Меняется динамически внутри сценария?



  • @intrapro, если Вам сильно нужно...правда это получится то же самое что я разбираюсь в ваших кодах)))

    /** 
    * @name VoiceTerminal - управление устройствами 
    * @desc При возникновении событий от голосового терминала выполнить действия 
    * @version 4  
    */
    
    //Константы для погоды
    const dt_s = Device("STEMP4_01");
    const dh_s = Device("SHUMIDITY4_01");
    
    //Константы для отопления
    const dt_supply = Device("ST_HEATING_SYS_01");
    const dt_hydro = Device("ST_HEATING_SYS_03");
    const dt_floor1 = Device("ST_HEATING1_02");
    const dt_floor2 = Device("ST_HEATING2_02");
    
    //Константы для вентиляции
    const sw_pvu= Device("SWITCH_PVU");
    
    //Константы для охраны
    const guard = Device("ACTOR_SECURITY_SYS00");
    
    //Константы для освещения
    const lamp_guest = Device("LAMP1_01");
    const lamp_kitchen = Device("LAMP1_03");
    const lamp_small_corridor = Device("LAMP1_05");
    const lamp_washroom = Device("LAMP1_06");
    const lamp_big_corridor = Device("LAMP1_08");
    const lamp_lobby = Device("LAMP1_09");
    const lamp_boiler_room = Device("LAMP1_11");
    const lamp_laundry_room = Device("LAMP1_12");
    const lamp_veranda = Device("LAMP4_01");
    const lamp_porch = Device("LAMP4_02");
    
    //Константы для других систем
    const garland_house = Device("ACTORA_GARLAND1_01");
    
    script({
      unit1: "voiceterminal1",
      unit2: "voiceterminal2",
      unit_com: "tts",
      string: "",   //Вспомогательная переменная
      device: "",   //Переменная для устройства
      terminal: "", //Переменная для имени терминала
      period: "",   //Переменная для периода дня
      arr: [],
      hello: ["Доброе утро!","Добрый день!","Добрый вечер!","Доброй ночи!"],
      answerToYouarehere: ["Конечно я тут!","А где я должна быть?","Нет, я в кинотеатре","Странный вопрос","Да, гуляю по дому..."],
      answerToHey: ["Чем могу помочь?","Что мне сделать для вас?","Какую команду выполнить?"],
      answerToWhoareyou: ["Я обученный интеллект вашего дома","Я просто программа","Я черная коробочка со светодиодами","Я маленький сервер"],
      answerToWelldone: ["Спасибо, мне очень приятно!","Да, я такая!","Ой, как приятно!","Спасибо за благодарность!"],
      answerToFool: ["Извините меня, я не специально!","Я что-то не так сделала?","Я иногда не понимаю что вы хотите от меня!","Прошу понять меня и простить!"],
      answerToThanks: ["Не за что!","Пожалуйста!","Пожалуйста, я старалась!","Нет проблем!","Велл кам!","Wellcom!"],
      doIt: ["Сделала!","Без проблем!","Выполнила!","Хорошо!","Все сделано!"],
      doNotKnowCommand: ["Я не знаю такой команды","Я не поняла вас","Что-то меня сбило","Вероятно я не верно услышала команду"],
      
      start(param) {
        const obj = JSON.parse(param);
        this.terminal = obj.terminal;
        this.qry = obj.qry.toLowerCase();
        this.rms = obj.rms_avg;
        
        //let message = [];
        
        //Для дебага входящих сообщений
        //this.log("### Receive message from - " +this.terminal+ ". Username - " +obj.username+ ". Qry - " +obj.qry+ ". RMS = " +obj.rms_avg);
        
        /*
        message.push(Date.now(), obj.terminal, obj.username, obj.qry.toLowerCase(), obj.rms_avg);
        this.arr.push(message);
        
        if(this.arr.length > 3)
        { //if(this.arr[1] - this.arr[0] < 100) {
          
          //}
          this.arr = [];
        }
        
        this.log(this.arr);
        this.log(this.arr.length);
        */
        
        //Установка громкости терминала в зависимости от периода дня
        this.SetVolumeTerminal();
        
        //Голосовой терминал VT1
        if(this.terminal == "VT1" || this.terminal == "VT2") {
          //Обработка фраз для формирования интеллектуального образа помощника
          if( this.qry.indexOf("ты тут") >= 0 || this.qry.indexOf("ты здесь") >= 0 ) {
            let number = this.GetRandomInt(0, this.answerToYouarehere.length);
            let answer = this.answerToYouarehere[number];
            
            if(obj.username == "aleksey") this.string = "Привет, Алексей! " +answer;
            else if(obj.username == "dima") this.string = "Привет, Дима! " +answer;
            else if(obj.username == "nadia") this.string = "Привет, Надежда! " +answer;
            else if(obj.username == "voiceterminal") this.string = "Да, но мои голосовые модели нужно усовершенствовать";
            else this.string = "Привет, я вас не узнала. Вы кто?";
            this.CommandToVoiceTerminal();
          }
          
          else if( this.qry.indexOf("привет") >= 0 ) {
            this.unit_com = "ask";
            let number = this.GetRandomInt(0, this.answerToHey.length);
            this.string = this.GetPeriodDay()+ " " +this.answerToHey[number];
            this.CommandToVoiceTerminal();
            this.unit_com = "tts";
          }
          
          else if( this.qry.indexOf("человек") >= 0 || this.qry.indexOf("кто ты") >= 0 ) {
            let number = this.GetRandomInt(0, this.answerToWhoareyou.length);
            this.string = this.answerToWhoareyou[number];
            this.CommandToVoiceTerminal();
          }
          
          else if( this.qry.indexOf("умница") >= 0 || this.qry.indexOf("молодец") >= 0 ) {
            let number = this.GetRandomInt(0, this.answerToWelldone.length);
            this.string = this.answerToWelldone[number];
            this.CommandToVoiceTerminal();
          }
          
          else if( this.qry.indexOf("дура") >= 0 ) {
            let number = this.GetRandomInt(0, this.answerToFool.length);
            this.string = this.answerToFool[number];
            this.CommandToVoiceTerminal();
          }
          
          else if( this.qry.indexOf("спасибо") >= 0 ) {
            let number = this.GetRandomInt(0, this.answerToThanks.length);
            this.string = this.answerToThanks[number];
            this.CommandToVoiceTerminal();
          }
          
          else if( this.qry.indexOf("как дела") >= 0 ) {
            if(guard.value) this.string = "Дом под охраной! ";
            else this.string = "Дом снят с охраны! ";
            
            //Подсчет проникновений и озвучивание
            let disturbance = global.get('Counter_OpenWindow');
            let disturbance_unit = this.FormLineEnd(disturbance, "проникновени", "n");
            if(disturbance < 1 || disturbance === undefined) this.string += "Проникновений не было!";
            else this.string += "Зафиксировано " +disturbance+ " " +disturbance_unit+ "!";
            
            this.CommandToVoiceTerminal();
          }
    
          //Обработка "время" и "времени"
          else if( this.qry.indexOf("сколько врем") >= 0 || this.qry.indexOf("какое врем") >= 0 ) {
            this.Time_Control();
          }
          
          //Обработка "погода"
          else if( this.qry.indexOf("погода") >= 0 ) {
            this.Weather_Control();
          }
          
          //Обработка "музык"
          else if( this.qry.indexOf("музык") >= 0 ) {
            if( this.qry.indexOf("включи") >= 0 || this.qry.indexOf("выключи") >= 0)
            
            /*
            this.unit_com = "get";
            this.string = "mstate";
            this.CommandToVoiceTerminal();
            */
            
            this.unit_com = "pause";
            this.string = "";
            this.CommandToVoiceTerminal();
            
            //Подтверждение со случайным выбором варианта
            this.unit_com = "tts";
            let number = this.GetRandomInt(0, this.doIt.length);
            this.string = this.doIt[number];
            this.CommandToVoiceTerminal();
          }
          
          //Обработка "температура"
          else if( this.qry.indexOf("температура") >= 0 ) {
            let dt = "";
            if( this.qry.indexOf("газов") >= 0 )        dt = dt_supply;
            else if( this.qry.indexOf("гидро") >= 0 )   dt = dt_hydro;
            else if( this.qry.indexOf("перв") >= 0 )    dt = dt_floor1;
            else if( this.qry.indexOf("втор") >= 0 )    dt = dt_floor2;
            else {
              this.unit_com = "ask";
              this.string = "Уточните какие показания вам нужны";
            }
            
            if(dt !== "") {
              let temp = dt.value.toFixed(1);
              let temp_unit = this.FormLineEnd(temp, "градус", "m");
              this.string = dt.name+ " равна " +temp+ " " +temp_unit;
            }
            this.CommandToVoiceTerminal();
            this.unit_com = "tts";
          }
          
          //Обработка "везде", "весь" и "все" (должен быть приоритет над свет/освещение и т.п.)
          else if( this.qry.indexOf("везде") >= 0  || this.qry.indexOf("веcь") >= 0 || this.qry.indexOf("вcе") >= 0 ) {
            if( this.qry.indexOf("свет") >= 0 || this.qry.indexOf("освещение") >= 0) this.Lamp_Control_All();
            this.exit();
            //if( this.qry.indexOf("электроприборы") >= 0 ) this.Energy_Control_All();
          }
          
          //Обработка команды включения/выключения света
          else if( this.qry.indexOf("свет") >= 0 || this.qry.indexOf("освещение") >= 0 ) {
            this.Lamp_Control();
          }
          
          //Обработка команды включения/выключения RGB-лент и гирлянд
          else if( this.qry.indexOf("ленту") >= 0 || this.qry.indexOf("гирлянду") >= 0 ) {
            this.Garland_Control();
          }
          
          //Обработка "давай спать"
          else if( this.qry.indexOf("давай спать") >= 0 ) {
            let device = new Array(lamp_guest,lamp_kitchen,lamp_washroom,lamp_big_corridor,lamp_lobby,lamp_boiler_room,lamp_laundry_room);
            //Выключение всех включенных ламп
            for(i=0; i < 7; i++) {
              if(device[i].isOn()) device[i].off();
            }
            //Включение ночного освещения
            if(lamp_small_corridor.isOff()) {
              lamp_small_corridor.on();
            }
            //Включение ночной громкости
            this.TTStoVTallOK();
            this.SetVolumeTerminal(50);
          }
          
          //Обработка "вентиляция" и "вентилятор"
          else if( this.qry.indexOf("вентиля") >= 0 || this.qry.indexOf("рекуператор") >= 0 ) {
            if( this.qry.indexOf("скорость 1") >= 0 ) sw_pvu.setValue(2);
            else if( this.qry.indexOf("скорость 2") >= 0 ) sw_pvu.setValue(3);
            else if( this.qry.indexOf("скорость 3") >= 0 ) sw_pvu.setValue(4);
            else if( this.qry.indexOf("включи") >= 0 ) sw_pvu.setValue(1);
            else if( this.qry.indexOf("выключи") >= 0 ) sw_pvu.setValue(0);
            this.string = "Выбран " +sw_pvu.name+ " - " +sw_pvu.stateName;
            this.CommandToVoiceTerminal();
          }
          
          else {
            //Команда "слушать без ключевого слова"
            this.unit_com = "ask";
            this.string = this.GetRandElementArr(this.doNotKnowCommand);
            this.CommandToVoiceTerminal();
            
            //Переход в обычный режим (распознавание с ключевым словом)
            this.unit_com = "tts";
          }
        }
      },
      
      //Функция устанавливает нужную громкость в зависимости от периода дня
      SetVolumeTerminal(level) {
        let time = this.GetPeriodDay('digit');
        
        if(this.period != time) {
          this.period = time;
          
          if(time == 0)       level = 70;   //Утро
          else if(time == 1)  level = 100;  //День
          else if(time == 2)  level = 70;   //Вечер
          else if(time == 3)  level = 50;   //Ночь
        }
        //Если уровень установлен, то даем команду на изменение громкости
        if(level !== undefined) {
          this.unit_com = "volume";
          this.string = level;
          this.CommandToVoiceTerminal();
          this.unit_com = "tts";
        }
      },
      
      //Функция возвращает текстовое (цифровое) значение периода дня
      GetPeriodDay(format) {
        let hello = new Array("Доброе утро!","Добрый день!","Добрый вечер!","Доброй ночи!");
        let date = new Date();
        let hour = date.getHours();
        let period = 0;
        
        if(hour > 6 && hour < 10)       period = 0; // Период 7-9
        else if(hour > 9 && hour < 20)  period = 1; // Период 10-19
        else if(hour > 19 && hour < 23) period = 2; // Период 20-22
        else                            period = 3; // Период 23-6
        
        //format == 'digit' или ''
        if(format == 'digit') return period;
        else return hello[period];
      },
      
      //Функция возвращает случайное целое число между min (включительно) и max (не включая max)
      GetRandomInt(min, max) {
        return Math.floor( Math.random() * (max - min)) + min;
      },
      
      //Функция получения случайного элемента из массива
      GetRandElementArr(array) {
        let number = this.GetRandomInt(0, array.length);
        return array[number];
      },
      
      //Функция формирования окончаний единиц измерений - если unit = "градус", то будет "градуса" и "градусов"
      FormLineEnd(val, unit, gender) {
        let part = 0;
        let string = "";
        let val_abs = Math.abs(val);
        
        if(val_abs > 20) part = val_abs % 10;
        else part = val_abs;
        
        //gender = m|f|n
        if(gender == "m") {
          if(part == 1) string = unit;
          else if(part > 1 && part < 5) string = unit+ "а";
          else string = unit+ "ов";
        }
        else if(gender == "f") {
          if(part == 1) string = unit+ "а";
          else if(part > 1 && part < 5) string = unit+ "ы";
          else string = unit;
        }
        else if(gender == "n") {
          if(part == 1) string = unit+ "е";
          else if(part > 1 && part < 5) string = unit+ "я";
          else string = unit+ "й";
        }
        return string;
      },
      
      //Функция для поиска нужного текста в строке qry от терминала
      FindTextOfQRY(text) {
        if(this.qry.indexOf(text) >= 0) return true;
        else return false;
      },
      
      //Функция передачи команды на терминал
      CommandToVoiceTerminal() {
        //if(this.rms)
        //this.pluginCommand({ unit:this.unit1, command:this.unit_com+ ":" +this.string });
        this.pluginCommand({ unit:this.unit2, command:this.unit_com+ ":" +this.string });
      },
      
      //Функция оповещения о текущем времени
      Time_Control() {
        let date = new Date();
        let hour = date.getHours();
        let minute = date.getMinutes();
        let hour_unit = this.FormLineEnd(hour, "час", "m");
        let minute_unit = this.FormLineEnd(minute, "минут", "f");
        this.string = "Сейчас " +hour+ " " +hour_unit+ " и " +minute+ " " +minute_unit;
        this.CommandToVoiceTerminal();
      },
      
      //Функция оповещения о текущей погоде за окном (запуск при наличии слов "погод")
      Weather_Control() {
        let temp = Math.round(dt_s.value);
        let hum = Math.round(dh_s.value);
        let temp_unit = this.FormLineEnd(temp, "градус", "m");
        let hum_unit = this.FormLineEnd(hum, "процент", "m");
        this.string = "Сейчас на улице " +temp+ " " +temp_unit+ " и влажность " +hum+ " " +hum_unit;
        this.CommandToVoiceTerminal();
      },
      
      //Функция управления освещением (запуск при наличии слов "свет" и "освещение")
      Lamp_Control() {
        //Поиск помещений по шаблону
        //switch()
        
        if( this.FindTextOfQRY("гост") )          this.device = lamp_guest;
        else if( this.FindTextOfQRY("кухн") )     this.device = lamp_kitchen;
        else if( this.FindTextOfQRY("мал") )      this.device = lamp_small_corridor;
        else if( this.FindTextOfQRY("сануз") )    this.device = lamp_washroom;
        else if( this.FindTextOfQRY("большо") )   this.device = lamp_big_corridor;
        else if( this.FindTextOfQRY("прихож") )   this.device = lamp_lobby;
        else if( this.FindTextOfQRY("котельн") )  this.device = lamp_boiler_room;
        else if( this.FindTextOfQRY("прачечн") )  this.device = lamp_laundry_room;
        else if( this.FindTextOfQRY("веранд") )   this.device = lamp_veranda;
        else if( this.FindTextOfQRY("крыльц") )   this.device = lamp_porch;
        else {
          this.TTStoVT("Уточните название помещения!");
          this.device = '';
          this.exit();
        }
        
        //Поиск действия по шаблону
        if( this.qry.indexOf("включи") >= 0 ) {
          if(this.device.isOff()) { this.device.on(); this.addListener(this.device, 'TTStoVTdevOn') }
          else this.TTStoVTdevisOn();
        }
        else if( this.qry.indexOf("выключи") >= 0 ) {
          if(this.device.isOn()) { this.device.off(); this.addListener(this.device, 'TTStoVTdevOff') }
          else this.TTStoVTdevisOff();
        }
        else this.TTStoVT("Уточните действие!");
      },
      
      //Функция управления RGB-лентами (запуск при наличии слов "лент" и "гирлянд")
      Garland_Control() {
        //Поиск помещений по шаблону
        if( this.qry.indexOf("дом") >= 0 ) this.device = garland_house;
        else if( this.qry.indexOf("крыльцо") >= 0 ) this.device = garland_porch;
        else if( this.qry.indexOf("гараж") >= 0 ) this.device = garland_garage;
        else {
          this.TTStoVT("Уточните название помещения!");
          this.device = '';
          this.exit();
        }
        
        //Поиск действия по шаблону
        if( this.qry.indexOf("включи") >= 0 ) {
          if(this.device.isOff()) {
            this.device.on();
            //this.addListener(this.device, 'TTStoVTdevOn');
          }
          else this.TTStoVTdevisOn();
        }
        else if( this.qry.indexOf("выключи") >= 0 ) {
          if(this.device.isOn()) {
            this.device.off();
            //this.addListener(this.device, 'TTStoVTdevOff');
          }
          else this.TTStoVTdevisOff();
        }
        else this.TTStoVT("Уточните действие!");
      },
      
      Lamp_Control_All() {
        let lighting = '1';
        let one_floor = '1';
        
        if( this.qry.indexOf("включи") >= 0 ) {
        this.doAll({place:'1,2,3,5', subs:lighting}, 'on');
        }
        else if( this.qry.indexOf("выключи") >= 0 ) {
          this.doAll({place:'1,2,3,5', subs:lighting}, 'off');
        }
        
        this.TTStoVTallComplete();
      },
      
      //Функция управления розетками (запуск при наличии слов "розетк" и "электричество")
      Socket_Control() {
        //Поиск помещений по шаблону
        if( this.FindTextOfQRY("гост") ) this.device = socket_guest;
        else if( this.qry.indexOf("кухн") >= 0 ) this.device = socket_kitchen;
        else if( this.qry.indexOf("сануз") >= 0 ) this.device = socket_washroom;
        else if( this.qry.indexOf("большо") >= 0 ) this.device = socket_big_corridor;
        else if( this.qry.indexOf("прачечн") >= 0 ) this.device = socket_laundry_room;
        else if( this.qry.indexOf("веранд") >= 0 ) this.device = socket_veranda;
        else if( this.qry.indexOf("крыльц") >= 0 ) this.device = socket_porch;
        else this.TTStoVT("Уточните название помещения!");
        
        //Поиск действия по шаблону
        if( this.qry.indexOf("включи") >= 0 ) {
          if(this.device.isOff()) { this.device.on(); this.addListener(this.device, 'TTStoVTdevOn') }
          else this.TTStoVTdevisOn();
        }
        else if( this.qry.indexOf("выключи") >= 0 ) {
          if(this.device.isOn()) { this.device.off(); this.addListener(this.device, 'TTStoVTdevOff') }
          else this.TTStoVTdevisOff();
        }
        else this.TTStoVT("Уточните действие!");
      },
      
      TTStoVTdevOn() {
        this.string = this.device.name+ " включен";
        this.CommandToVoiceTerminal();
        this.exit();
      },
    
      TTStoVTdevOff() {
        this.string = this.device.name+ " выключен";
        this.CommandToVoiceTerminal();
        this.exit();
      },
      
      TTStoVTdevisOn() {
        this.string = this.device.name+ " уже был включен!";
        this.CommandToVoiceTerminal();
        this.exit();
      },
    
      TTStoVTdevisOff() {
        this.string = this.device.name+ " уже был выключен!";
        this.CommandToVoiceTerminal();
        this.exit();
      },
      
      TTStoVT(text) {
        this.string = text;
        this.CommandToVoiceTerminal();
      },  
      
      TTStoVTWhatPlace() {
        this.string = "Уточните название помещения!";
        this.CommandToVoiceTerminal();
      },
      
      TTStoVTallComplete() {
        let number = this.GetRandomInt(0, this.doIt.length);
        this.string = this.doIt[number];
        this.CommandToVoiceTerminal();
      },
      
      TTStoVTallOK() {
        this.string = "Я готова";
        this.CommandToVoiceTerminal();
      }
    });
    
    

    Устройство меняется динамически внутри сценария (см.функцию - Garland_Control()). В данном случае сделал функцию для включения/выключения RGB-лент, которые управляются актуатором аналоговым. В данном конкретном случае - const garland_house
    При этом функция Lamp_Control() работает без нареканий. Поэтому сделал вывод что есть какая-то проблема с актуатором аналоговым.



  • @Alex_Jet, ОЧЕНЬ изобретательно и креативно 👍 👍 👍
    И вполне рабочая схема:
    Сформировать команду на основе фразы -> передать команду -> установить слушателя для устройства.
    А когда устройство переключится (сработает слушатель) - отрапортовать о выполнении.

    Единственное тонкое место здесь - если устройство по какой-то причине не ответит, то сценарий зависнет.
    Потому что, устанавливая слушателя, мы оставляем сценарий запущенным. Он ждет события, и не выходит.
    Обычно, параллельно со слушателями, целесообразно устанавливать таймер, чтобы сценарий все же завершился. Типа "не шмогла" 🙂

    Почему в конкретном случае не срабатывает - нужно смотреть. В скрипте garland_porch и garland_garage не определены. Но Вы говорите, что команда на включение уходит, то есть идете по ветке garland_house. Можно посмотреть параллельно в отладчике плагина - что приходит в ответ на команду.
    Но таймер нужен в любом случае: если устанавливается слушатель - нужно предусмотреть и другой выход.



  • Участник @intrapro написал в Сценарии - новая версия API:

    В скрипте garland_porch и garland_garage не определены. Но Вы говорите, что команда на включение уходит, то есть идете по ветке garland_house. Можно посмотреть параллельно в отладчике плагина - что приходит в ответ на команду.
    Но таймер нужен в любом случае: если устанавливается слушатель - нужно предусмотреть и другой выход.

    Да, я иду по ветке garland_house (определение фраз очень точное!). В отладчике плагина megad - действительно не додумался посмотреть......и сейчас понял, что там нечего смотреть! Поскольку управление WS281x хоть и нативное, но одностороннее! Как итог - ответа от контроллера нет, а плагин ждет его. Хотя!!! Опять же - я управляю всего лишь актуатором и косвенно самой лентой. А актуатор в свою очередь завязан на сценарий управления и плагин megad тут не причем! То есть здесь нет отклика именно от актуатора. Мне кажется, что Вы сами можете воспроизвести такую ситуацию.

    С таймером согласен - это "байпас" сценария, правда пока не могу придумать логику чтобы было все по взрослому (если завис слушатель, то сказать "Не смогла", а если не завис, то не говорить "Не смогла"...).

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



  • Участник @Alex_Jet написал в Сценарии - новая версия API:

    То есть здесь нет отклика именно от актуатора.

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

    С таймером согласен - это "байпас" сценария, правда пока не могу придумать логику чтобы было все по взрослому (если завис слушатель, то сказать "Не смогла", а если не завис, то не говорить "Не смогла"...).

    Если не завис, то все OK, сценарий у Вас сразу выходит. То есть говорить ничего не придется.
    Цель таймера - страховка слушателей. При добавлении слушателя просто всегда добавлять таймер (на время отклика*2, например) и по таймеру выходить.

    А так - уже очень привыкли всей семьей к голосовому управлению))

    Да, к хорошему быстро привыкаешь :).



  • Участник @intrapro написал в Сценарии - новая версия API:

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

    Так я это вижу как в отладчике сценария (ACTORA_GARLAND1_01 on), так и визуально (RGB-лента начинает работать). То же при выключении. Вы не пробовали сымитировать ситуацию?



  • Коллеги, помимо вышеописанного)) Решил ребенка немного научить программировать! А когда это все сразу можно применить на практике - это вообще здорово и особенно увлекает ребенка)))
    Однако я предпочитаю кодить, а ему это просто не реально поскольку только научился немного читать))) поэтому решил начать с объектно-ориентированного программирования, то есть с блок-схем. Начали изучать с нуля. И вот когда сценарий уже стал немного более сложным я сам не смог понять как мне сделать - чтобы или по окончании таймера или по выключению актуатора выключить свет с помощью блока ALL.
    Блок-схема.png

    И да, кстати, считаю что название блоков нужно как-то привести к их названию в дереве. Например, если блок ACTION, то в дереве должен называться "Действие", либо наоборот - раз в дереве "Команда устройства", то название блока - COMMAND. Если Команда группе устройств, то COMMAND_ALL.

    Update: к OFF актуатора ACTOR_DIMA подключил еще один такой же блок ALL OFF (как на скриншоте выше) - вижу, что скрипт верный, все условия есть. Но почему-то в отладчике нет сработки ACTOR_DIMA при его принудительном выключении через веб!!! Соответственно, лампы не отключаются... В чем может быть проблема?



  • Добрый день, подскажите как в блок-схеме проверить статус устройства, actor в каком положении 0,1...?



  • @Alex_Jet, Добрый день!
    К сожалению, пока в блоках такая задача не реализуется, не успевают наши технологии за ребенком 🙂
    Причина - через блоки не генерируется код для слушателя (addListener)

    Красный блок - это триггер запуска, проверка isOn/isOff происходит в функции start.
    Потом взводится таймер, в этот период выключение лампы обработано не будет, так как сценарий остался активным, но слушателей в нем нет.
    Выход - сделать отдельный сценарий: при выключении ACTOR_DIMA => сделать ALL OFF
    Но надо иметь в виду, что первый сценарий тоже сделает свою работу, когда таймер досчитает до конца.


Авторизуйтесь, чтобы ответить