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



  • Не могли бы вы сделать инструкцию по дополнительным параметрам устройств?
    Пытаюсь сделать числовой доп.параметр:

    const meterDay = Device("METER6", "Стоимость кВт", [
      {"name":"rkvt", "note":"Стоимость за кВт", "type":"Number", "val":4.47}
      ]); //Счетчик дневных показаний
    

    Параметр добавляется, но его нельзя редактировать. Кроме того, не получается обратиться к нему как к свойству из сценария. Например, meterD.rkvt недоступен.
    Подскажите как правильно объявить параметр, чтобы через боковое меню был доступен ввод значения, либо кнопки "включить/выключить", как использовать значение параметра в сценарии?



  • @homa
    Добрый день, добавьте скобки после isOn, isOff:

    if ( SENSOR1.isOn ) {   // должно вызывать ошибку, так как это не свойство, а функция 
    if ( SENSOR1.isOn() ) {   // Это правильный вариант
    

    Но действительно, без скобок ошибки нет, срабатывает в любом случае 😞



  • Каждый раз при создании мультисценария наступаю на одни и те же грабли.
    Нужно объявить тип устройства в первых строчках.
    И нигде в документации нет информации какое устройство к какому типу относится, и как этот тип правильно пишется.
    Ну сделайте пожалйста.

    А то при создании датчик открытия двери обзывается SGERKON, и в простом сценарии он тоже SGERKON, а в мультисценарии он оказывается должен быть SensorD.
    Ну вот как я это должен был узнать, кроме прямого перебора вариантов? Как?



  • @homa, вы сделали все верно, тип только должен быть с маленькой буквы, тогда редактирование будет работать:

    {"name":"rkvt", "note":"Стоимость за кВт", "type":"number", "val":4.47}
    

    По типам - пока реализовано только три типа для ввода:

    • "type": "number" (число, в том числе вещественное),
    • "type":"cb" (checkbox)
    • "type":"time" (для ввода временных интервалов).

    Любой другой тип, включая string, выводится как readOnly (без возможности редактирования)

    Из сценария доп. свойства доступны не напрямую, а через функции getParam, setParam:

    let x = meterD.getParam("rkvt");
    ......
    ..... 
    meterD.setParam("rkvt", x*0.9 );
    


  • @Erik
    Документация - это действительно наше слабое место. Но мы работаем над этим 🙂

    В данном случае все просто - объявляется не тип, а класс, и их всего 5:
    "SensorD" - Датчик дискретный
    "SensorA" - Датчик аналоговый
    "ActorD" - Актуатор дискретный
    "ActorA" - Актуатор аналоговый
    "Meter" - Счетчик

    Класс выводится в таблице устройств в столбце "Класс", а этот список можно найти в разделе Сценарии рубрика Классы устройств



  • А можно узнать такую вещь - когда мой голосовой терминал распознает фразу, то он кидает ее на сервер, плагин принимая команду терминала запускает сценарий:

    06.11 00:19:38.225 voiceterminal1: 192.168.11.51 => localhost:11051 HTTP GET /command.php?terminal=VT1&rms_max=2201&rms_min=987&username=aleksey&rms_avg=1293&qry=Включи+свет
    06.11 00:19:38.226 voiceterminal1: 192.168.11.51 <= localhost:11051 
    06.11 00:19:38.226 voiceterminal1: { type: 'startscene',
      id: 'VoiceTerminal_Temp',
      arg: '{"terminal":"VT1","rms_max":"2201","rms_min":"987","username":"aleksey","rms_avg":"1293","qry":"Включи свет"}' }
    06.11 00:19:38.228 IH: plugin command { unit: 'voiceterminal1',
      command: 'ask:Уточните название помещения!',
      type: 'command' }
    06.11 00:19:38.230 IH: startscene VoiceTerminal_Temp
    

    Тут видно, что сценарий запустился, отработал и плагину пошла команда 'ask:Уточните название помещения!'. Но почему после этого IH вдруг снова запускает сценарий (06.11 00:19:38.230 IH: startscene VoiceTerminal_Temp)?

    В итоге в отладчике сценария вижу вот это и моя задумка не работает...

    06.11 00:19:38.227 Started
    06.11 00:19:38.228 plugincCommand { unit: 'voiceterminal1',
      command: 'ask:Уточните название помещения!' }
    06.11 00:19:38.229 exit
    06.11 00:19:38.229 Stopped
    06.11 00:19:38.230 exit
    

    По идее последних Stopped и exit быть не должно. Такое ощущение, что IH принудительно запускает сценарий без входных данных и мои все переменные сценария обнуляются.



  • @Alex_Jet, Думаю, сценарий повторно не запускается, просто логирование происходит чуть позже запуска (на 3 мсек):

    06.11 00:19:38.226 voiceterminal1: { type: 'startscene',...   // Команда на запуск сценария
    06.11 00:19:38.227 Started // Запустили 
    06.11 00:19:38.228 IH: plugin command { unit: 'voiceterminal1',command: 'ask:Уточните...  // Работает сценарий
    06.11 00:19:38.230 IH: startscene VoiceTerminal_Temp // Фиксируем, что был запуск сценария
    

    То есть запустили сценарий, а потом зафиксировали в журнал. Возможно, фиксировать запуск правильнее до фактического запуска, но есть вероятность, что сценарий не запустится, поэтому сделано так

    Количество запусков можно посмотреть в Рабочих сценариях. После редактирования сценария этот счетчик сбрасывается

    Что касается Stopped и exit:
    Stopped в паре со Started один. Да, exit лишний, но там наверно есть прямой this.exit(), поэтому опять же особенность логирования



  • @intrapro а как одному устройству добавить несколько свойств? на разделить "запятая" ругается



  • И следом вопрос корректно ли объявлять одно и тоже свойство для одного и того же устройства в разных сценариях, или есть какие-то другие варианты обращения к ранее объявленным свойствам



  • @homa, вот так все работает:

    const dev1 = Device("_UNIT_voiceterminal1", [
      {"name":"uptime", "note":"Времы работы", "type":"string", "val":""},
      {"name":"status", "note":"Состояние", "type":"string", "val":""},
      {"name":"updater", "note":"Обновления", "type":"string", "val":""},
      {"name":"set_volume", "note":"Громкость терминала", "type":"number", "val":50},
      {"name":"set_music_volume", "note":"Громкость плеера", "type":"number", "val":50},
      {"name":"last_update", "note":"Update", "type":"string", "val":""}
      ]);
    


  • @homa, в принципе корректно. У устройства будут свойства с одинаковым названием, но отнесенные к разным сценариям:
    Устройство_Дополнительные_Параметры.png



  • @Alex_Jet идея в том, чтобы изменять из разных сценариев одно свойство... выходит не выходит)



  • @intrapro, this.exit() действительно есть в функции сценария, но перед этим переменной сценария flag_com присваивается 1, что указывает на то что не надо выполнять основное ветвление if, а надо выполнить else. Типа вот такого:

    if(!this.flag_com) {
      //Парсим входные данные и в соответствии с ними выполняем команды..
    }
    else {
     //Повторно заходим в функцию чтобы выполнить действие с уточненным названием помещения
     this.Lamp_Control();
    }
    

    Если функция отработала успешно, то присваиваем flag_com=0, чтобы сценарий работал по основному ветвлению if. В общем, попробую добавить логирование в сценарий...просто не хотелось журнал забивать не нужной информацией:(



  • @homa, тогда нужно использовать глобальные переменные. Функционал есть, 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();
        }
    });
    

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