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



  • Подскажите, пожалуйста.
    Есть датчик универсальный аналоговый. Привязан к датчику CO2 T6703. У датчика определены состояния: до 400, до 600, до 800, до 1000 и более 1000. Для каждого состояния меняется цвет иконки. На мнемосхеме все работает прекрасно- отображаются значения, меняется цвет иконки. Вопрос в другом. Решил сделать сценарий, отслеживающий изменение состояния. В системе команд есть функция x.isChanged (имя свойства). Но конструкция
    startOnChanged(sens, sens.isChanged('state'));
    не работает. В ошибках рабочего сценария пишет, что функция не определена. Если убрать условие отслеживания состояния, то сценарий отрабатывает по изменению значения каждую минуту. Хотел сократить число запусков. Подскажите, что не так



  • @int144 Вы все верно сделали, но в v4 сценариев мы по техническим причинам убрали device.isChanged(prop), заменив его на this.isChanged(device, prop,value)
    То есть эту возможность в startOnChange сейчас применить нельзя.
    Можно проверить уже внутри start:

    // Проверить, что сценарий запустился из-за изменения состояния
    if (this.isChanged(sens, 'state')) {
    ....
    } 
    // Можно проверить, что переключился в определенное состояние
    if (this.isChanged(sens, 'state', 1)) {
    ...
    }
    

    Извините за неточности в документации 😞



  • @intrapro , спасибо за быстрый ответ. Жаль, конечно, что нет возможности использовать в условии, но так тоже пойдет. Буду иметь в виду



  • Подскажите как можно во время работы сценария блокировать повторный запуск сценария? Есть физическая кнопка которая запускает сценарий, нужно что бы во время работы сценария не было возможности повторного запуска сценария.



  • Пользователь @amgstone написал в Сценарии - новая версия API:

    Подскажите как можно во время работы сценария блокировать повторный запуск сценария? Есть физическая кнопка которая запускает сценарий, нужно что бы во время работы сценария не было возможности повторного запуска сценария.

    Через доп актуатор. Это прекрасная замена глобальным переменным.

    На старте скрипта проверяете значение этого актуатора. Если 1 - сразу выходите из скрипта. Если 0 - присваиваете ему значение 1, и продолжаете дальше. Потом делаете все, что должен сделать скрипт, а последгним шагом возвращаете этому актуатору значение 0.



  • Не совсем то что надо, у меня ролокасеты, актуатор должен блокироватся на опредиленое время, чтобы ролета могла опустится или поднятся.



  • @amgstone
    Добавьте в конце перед возвращением актуатору значения 0 таймер на нужное время.



  • Команда this.exit() может применяться для прерывания сценария в любом его месте?

    столкнулся с тем, что

    if (device.isOff() )  this.exit() ;  // если выключено - выйти из сценария
    
    

    в основном теле сценария не работает - сценарий бодро шлепает по коду дальше.
    В то же время this.exit() помещенная , например, в функцию таймера прерывает сценарий.



  • @alesle Да, Вы правы, внутри функции start this.exit() не работает. Чтобы завершить функцию start, достаточно сделать return.

    this.exit() предназначен, чтобы завершить асинхронную деятельность сценария из функций - обработчиков (запущенных из start). Логика такая:

    • Метод start() вызывается, когда движок запускает сценарий (по триггерам, по расписанию, интерактивно) и тот становится активным.

    • Если внутри сценария просто последовательность действий, он отработает и сразу завершится (станет не активным). При следующем запуске он опять начнется со start(). Большая часть сценариев работает именно так и 99,9% времени находятся в неактивном состоянии. Напротив таких сценариев не бывает зеленых галочек в Рабочих сценариях.

    • Но если сценарий взводит таймеры и/или устанавливает слушателей событий, сценарий не завершается, а остается активным, следит за своими таймерами и устройствами "изнутри", запускает функции-обработчики как реакцию на отслеживаемые события. Пока сценарий активен (зеленая галочка), start по триггеру уже не работает.

    Чтобы завершить такой сценарий, из обработчика нужно выполнить команду this.exit().
    По этой команде все его таймеры и слушатели удаляются и сценарий станет не активным. При следующем запуске опять выполнится start()



  • @intrapro ,
    Огромное спасибо за разяснения!!!



  • Доброго времени суток! Пытаюсь реализовать вывод показаний скорости ветра. Датчик импульсный, 1 импульс= 2,4 км/час. Только как их преобразовать в скорость? Вероятно нужен сценарий, где выводятся показания счетчика за отведенное время (секунда, минута, час) и происходит его обнуление. Если кто решал подобную задачу, прошу поделиться!



  • @sergeyygr, думаю, что нужно делать так же как для счётчика газа. Писал об этом - тут
    Главное верно определить вес импульса чтобы получить значения сразу в м/с или км/ч.
    Хотя мне не до конца понятен принцип работы такого датчика. Он самостоятельно каждую секунду выдает сколько то импульсов, которые соответствуют скорости ветра в текущую единицу времени? Если так, то лучше "захватывать" эти показания сценарием, пересчитывать и присваивать датчику. Покажите что выдает отладчик на канале к которому подключен датчик?
    Но опять же если все так как я написал выше, то можно пересчитывать показания с помощью формулы или через вкладку "Обработка значений" канала.



  • Пользователь @Alex_Jet написал в Сценарии - новая версия API:

    @sergeyygr, думаю, что нужно делать так же как для счётчика газа. Писал об этом - тут
    Главное верно определить вес импульса чтобы получить значения сразу в м/с или км/ч.
    Хотя мне не до конца понятен принцип работы такого датчика. Он самостоятельно каждую секунду выдает сколько то импульсов, которые соответствуют скорости ветра в текущую единицу времени? Если так, то лучше "захватывать" эти показания сценарием, пересчитывать и присваивать датчику. Покажите что выдает отладчик на канале к которому подключен датчик?
    Но опять же если все так как я написал выше, то можно пересчитывать показания с помощью формулы или через вкладку "Обработка значений" канала.

    Да, спасибо, так и настроил. Только нужна сумма импульсов в определенный промежуток времени, затем сброс показаний и опять сумма импульсов. Если считать метры в секунду, то вес импульса равен 0,667. Принцип датчика как счетчик воды, только в запросе m=2 не нужно, скорость большая, режим raw в канале контроллера выключен, дребезга нет. В общем задача сходна с тем, что нужно кроме общего расхода воды узнать ее расход в час и значение должно быть присвоено и постоянно обновляться в иконке датчика.
    Датчик примерно такой - https://www.ab-log.ru/smart-house/weather-station/megad-2561-wind-sensors



  • @sergeyygr, так может быть просто сервером каждую секунду опрашивать канал 5 раз, вычисляя приращение счётчика канала. Далее сортировать значения, откидывать "боковые", усреднять оставшиеся - то есть будем получать "правильное" усреднённое значение в м/с каждые 5 секунд. Причем все это действие можно проводить раз в минуту/5минут.
    Если вам удобнее км/ч, то в формуле можно усреднённое значение в м/с умножать на 3.6

    А вообще нужно в iH либо написать скрипт подобный или сделать то же средствами канала плагина MegaD.
    Коллеги, @intrahouse, @intrapro, помогите с помощью iH разрешить вот такой скрипт:

    <?
    $last_cnt = 0;
    while(true)
    {
        $state = explode("/", file_get_contents("http://192.168.0.14/sec/?pt=7&cmd=get"));
        $cnt = $state[1];
        if ( $last_cnt != $cnt )
        $wind_speed = ($cnt - $last_cnt) * 0.0875 + 0.1;
        else
        $wind_speed = 0;
        echo $cnt." - $wind_speed m/s";
        $last_cnt = $cnt;
        if ( $cnt > 1000 )
        {
            $state = explode("/", file_get_contents("http://192.168.0.14/sec/?pt=7&cnt=0"));
            $last_cnt = 0;
        }
        sleep(1);
    }
    ?>
    


  • Пользователь @Alex_Jet написал в Сценарии - новая версия API:

    @sergeyygr, думаю, что нужно делать так же как для счётчика газа. Писал об этом - тут
    Главное верно определить вес импульса чтобы получить значения сразу в м/с или км/ч.
    Хотя мне не до конца понятен принцип работы такого датчика. Он самостоятельно каждую секунду выдает сколько то импульсов, которые соответствуют скорости ветра в текущую единицу времени? Если так, то лучше "захватывать" эти показания сценарием, пересчитывать и присваивать датчику. Покажите что выдает отладчик на канале к которому подключен датчик?
    Но опять же если все так как я написал выше, то можно пересчитывать показания с помощью формулы или через вкладку "Обработка значений" канала.

    Добрый день! А какое практическое значение имеет функция "Период опроса" в счетчике? Думаю в моем случае было бы полезно счетчику дать возможность обнулять с заданным периодом, опрашивать и выводить последние значение. Задача была решена!!!



  • @sergeyygr Добрый день!
    Пока не совсем в теме по датчику. Но если воспроизвести скрипт от @Alex_Jet, то получится примерно так:

    1. Опрашиваем датчик с заданным интервалом из сценария (в каналах опрос не нужен, т е период =0)
    2. По магической формуле 🙂 считаем значение, используя значение счетчика
    3. Периодически сбрасываем счетчик
    const WindSensor = Device('MyWindSensor');
    
    script({
      last_cnt:0,  // Эту переменную нужно сохранять, поэтому ее выносим и далее исп как this.last_cnt
    
      boot() {
          return true; // Сценарий будет запускаться при старте сервера
      }, 
    
      start() {
          this.resetCount();
          // Взвести таймер - опрос раз в секунду, можно чаще (0.5 = 500 мсек)
          this.startTimer('T1', 1, 'onTimer');
      },
      
      resetCount() {
        // Передать запрос на сброс счетчика
        this.pluginCommand({unit:'megad1', command:{url:'/sec/?pt=7&cnt=0'}});
      }, 
    
      onTimer() {
        // Передать запрос на чтение, ответ придет в функцию  getResponse
        this.pluginCommand({unit:'megad1', command:{url:'/sec/?pt=7&cmd=get', onResponse:'raw'}}, 'getResponse');
        this.startTimer('T1', 1, 'onTimer'); // Следующий запрос 
      },
    
      getResponse(body) {
        // body = OFF/2
        this.log('getResponse body= '+body); // Для отладки
        if (!body) return;
    
        const arr = body.split('/');
        if (arr.length<2) {
          this.log('Ожидается значение счетчика после символа  "/"');
          return; // Ошибка, значение не получено
        }  
    
        let cnt = arr[1];
        if ( this.last_cnt != cnt ) {
          let wind_speed = (cnt - this.last_cnt) * 0.0875 + 0.1;
          this.last_cnt = cnt;
          this.assign(WindSensor, 'value', wind_speed);
        }
      
        if ( cnt > 1000 ) {
          this.resetCount();
          this.last_cnt = 0;
        }
      }
    });
    
    • Сценарий будет запускаться при старте сервера
    • будет работать постоянно, потому что таймер все время перевзводится
    • не имеет триггеров, то есть при необходимости его надо взводить/останавливать вручную (Запустить сценарий/ Остановить сценарий)

    Потестируйте, возможно есть косяки или не все учтено



  • Пользователь @intrapro написал в Сценарии - новая версия API:

    @sergeyygr Добрый день!
    Пока не совсем в теме по датчику. Но если воспроизвести скрипт от @Alex_Jet, то получится примерно так:

    1. Опрашиваем датчик с заданным интервалом из сценария (в каналах опрос не нужен, т е период =0)
    2. По магической формуле 🙂 считаем значение, используя значение счетчика
    3. Периодически сбрасываем счетчик
    const WindSensor = Device('MyWindSensor');
    
    script({
      last_cnt:0,  // Эту переменную нужно сохранять, поэтому ее выносим и далее исп как this.last_cnt
    
      boot() {
          return true; // Сценарий будет запускаться при старте сервера
      }, 
    
      start() {
          this.resetCount();
          // Взвести таймер - опрос раз в секунду, можно чаще (0.5 = 500 мсек)
          this.startTimer('T1', 1, 'onTimer');
      },
      
      resetCount() {
        // Передать запрос на сброс счетчика
        this.pluginCommand({unit:'megad1', command:{url:'/sec/?pt=7&cnt=0'}});
      }, 
    
      onTimer() {
        // Передать запрос на чтение, ответ придет в функцию  getResponse
        this.pluginCommand({unit:'megad1', command:{url:'/sec/?pt=7&cmd=get', onResponse:'raw'}}, 'getResponse');
        this.startTimer('T1', 1, 'onTimer'); // Следующий запрос 
      },
    
      getResponse(body) {
        // body = OFF/2
        this.log('getResponse body= '+body); // Для отладки
        if (!body) return;
    
        const arr = body.split('/');
        if (arr.length<2) {
          this.log('Ожидается значение счетчика после символа  "/"');
          return; // Ошибка, значение не получено
        }  
    
        let cnt = arr[1];
        if ( this.last_cnt != cnt ) {
          let wind_speed = (cnt - this.last_cnt) * 0.0875 + 0.1;
          this.last_cnt = cnt;
          this.assign(WindSensor, 'value', wind_speed);
        }
      
        if ( cnt > 1000 ) {
          this.resetCount();
          this.last_cnt = 0;
        }
      }
    });
    
    • Сценарий будет запускаться при старте сервера
    • будет работать постоянно, потому что таймер все время перевзводится
    • не имеет триггеров, то есть при необходимости его надо взводить/останавливать вручную (Запустить сценарий/ Остановить сценарий)

    Потестируйте, возможно есть косяки или не все учтено

    Спасибо!
    Настроил, в иконке показания суммируются.
    Вот отладчик.
    Снимок.PNG
    Вот лог.
    Снимок2.PNG
    Вот иконка.
    Снимок1.PNG



  • @sergeyygr
    Что я делаю не так?



  • @sergeyygr А у вас тип устройства какой? Счетчик? Нужен обычный аналоговый датчик.



  • Пользователь @intrapro написал в Сценарии - новая версия API:

    @sergeyygr А у вас тип устройства какой? Счетчик? Нужен обычный аналоговый датчик.

    Все заработало! Спасибо за это существенное уточнение!


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