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



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

          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
    Но надо иметь в виду, что первый сценарий тоже сделает свою работу, когда таймер досчитает до конца.



  • @amgstone, Добрый день!
    Для проверки статуса нужно добавить желтый блок .
    Он добавляется с вкладки Операции : Свойство устройства
    Затем для этого блока выбираете устройство и свойство:
    ex3.png

    В результате логика такая: когда выключится LAMP_1_1 (красный блок - триггер), и при этом LAMP2 (желтый блок) включена , то сделать то-то



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



  • Выяснил один момент - параметрам актуаторов/датчиков нельзя присваивать в качестве name значение "log"! Иначе при чтении значения данного параметра отобразиться лишь [object Object],[object Object],[object Object],[object Object]...

    Вопрос в другом - как актуатору или датчику из сценария присвоить значение ошибки, чтобы на его значке в вебе отображался индикатор аварии (восклицательный знак в красном треугольнике)? Задача - есть индикатор (актуатор дискретный) постановки на охрану. При его включении (on) проверяем какие значения имеют глобальные константы, если они не в норме, то индикатор выключаем (off) и показываем на нем ошибку.



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

    @intrapro, это просто жесть...я думал что Ваш "блокли" уже имеет достаточный функционал...

    Там до сих пор нет арифметики!!!!
    И при сложной структуре блоков часть выпадает, и не выполняется в скрипте.

    Поэтому учить ребенка придется с синтаксиса. 😞



  • @intrapro, по global переменным сценариев. Можно сделать чтобы значение 0 отображалось как 0, а не "-"? Не хватает возможности описания переменных.



  • Подскажите как можно заблокировать кнопку актора на екране от нажатия во время работы сценария или блокировать по таймеру



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

    Выяснил один момент - параметрам актуаторов/датчиков нельзя присваивать в качестве name значение "log"! Иначе при чтении значения данного параметра отобразиться лишь [object Object],[object Object],[object Object],[object Object]...

    Да, все верно. Каждое устройство имеет свойство log - массив записей журнала.

    Вопрос в другом - как актуатору или датчику из сценария присвоить значение ошибки, чтобы на его значке в вебе отображался индикатор аварии (восклицательный знак в красном треугольнике)? Задача - есть индикатор (актуатор дискретный) постановки на охрану. При его включении (on) проверяем какие значения имеют глобальные константы, если они не в норме, то индикатор выключаем (off) и показываем на нем ошибку.

    Ошибка устройства - это свойство "error". Можно использовать assign.

       if (<ваше условие>) {
              this.assign(sensor, 'error', 0);
       } else {
              this.assign(sensor, 'error', 1);    
       }  
    

    Только надо иметь в виду, что такое прокатит только с виртуальным устройством (в Вашем случае индикатор ведь виртуальный?). Если устройство связано с каналом, то при поступлении данных с канала ошибка будет сброшена.



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

    Подскажите как можно заблокировать кнопку актора на екране от нажатия во время работы сценария или блокировать по таймеру

    Можно использовать команду устройства setBlk

    actor1.setBlk(1); // В начале работы - заблокировали
    // ...
    actor1.setBlk(0); // В конце - разблокировали
    

    Хотя в документации написано, что работает только для сенсоров 🙂 , для актуаторов тоже работает. Нужно только установить флаг: Устройство может быть заблокировано
     actor_blk.png

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



  • @intrapro не совсем так, нужно: нажимаю на актор и пока скрипт не отработал что бы на нажатия на актор не реагировало пока не отработает скрипт.



  • @intrapro, да, он виртуальный! Спасибо, буду понимать что это свойство устройства. А, кстати, у устройства есть 4 индикатора - error, auto...и еще 2. Этими двумя как-то можно рулить?


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