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



  • У меня проблема, которую я не могу осознать.

    Мультисценарий

    script({
        start(step) {
          step = Number(step);
           let newvalue = step;
           ActUst.setValue(newvalue);
        } 
    });
    

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

    Актуатор по модбасу присоединен к параметру контроллера "температура антизамерзания". Этот параметр содержит значение температуры на улице, ниже которой насос в контуре станет постоянно включенным. Если выше включается/выключается по необходимости, если ниже - всегда гоняет жижу, чтобы не замерзла. Такая функция.
    Соответственно, значение может быть от -25 до +5.
    Но на 0 и выше скриптом назначается, а на любое отрицательное - нет.

    Решил сделать другой мультисценарий.
    Просто строку

    ActUst.setValue(-25)
    

    Ошибок нет. Но этот сценарий не отображается в меню "параметры" у кнопки. Перезагрузка IH не помогла.

    Если назначаю отрицательное значение напрямую на контроллере - они считываются по модбас, и отображаются в IH. Наоборот - только положительные.

    Что за магия?



  • Если управлять этим же скриптом актуатором, не подключенным к модбас, все работает.



  • @Erik, добрый день
    Возможно, назначается не тот тип переменной при записи по modbus отрицательных чисел. Посмотрите в отладчике плагина в момент передачи команды на запись. Там должны быть сообщения:

    Command ..... received. Data: ....
    // Потом
    WRITE: unitId =..., FC = 6, address =....
    


  • вот успешное

    29.02 13:49:06.536 IH: command [ { dn: 'ACTORA84', prop: 'set', val: 5 } ]
    29.02 13:49:06.538 IH: send { type: 'act',
      data: 
       [ { chan: 'T.Antizam.Ku',
           id: 'T.Antizam.Ku',
           vartype: 'int16',
           usek: false,
           ks: 100,
           ks0: 0,
           gr: false,
           pollp: true,
           value: 50,
           desc: 'AO',
           kh0: 0,
           address: '1321',
           fcr: '3',
           useactions: false,
           kh: 100,
           nofb: false,
           unitid: 1,
           calc_outfn: [Function: anonymous],
           command: 'set' } ] }
    29.02 13:49:06.542 modbus1: Command to send: [ { chan: 'T.Antizam.Ku',
        id: 'T.Antizam.Ku',
        vartype: 'int16be',
        usek: false,
        ks: 100,
        ks0: 0,
        gr: false,
        pollp: true,
        value: 50,
        desc: 'AO',
        kh0: 0,
        address: 1321,
        fcr: '3',
        useactions: false,
        kh: 100,
        nofb: false,
        unitid: 1,
        command: 'set' },
      53,
      54,
      55,
      56,
      57,
      58,
      59,
      60,
      61,
      62,
      63,
      64,
      65,
      66,
      67,
      68,
      69,
      70,
      71 ]
    29.02 13:49:06.557 modbus1: WRITE: unitId = 1, FC = 6, address = 1321 (0x529), value = 50
    29.02 13:49:06.558 modbus1: writeSingleRegister: address = 1321 (0x529), value = 50
    29.02 13:49:06.559 modbus1: Write result: { address: 1321, value: 50 }
    

    а вот ошибки

    29.02 13:49:08.683 IH: command [ { dn: 'ACTORA84', prop: 'set', val: -20 } ]
    29.02 13:49:08.684 IH: send { type: 'act',
      data: 
       [ { chan: 'T.Antizam.Ku',
           id: 'T.Antizam.Ku',
           vartype: 'int16',
           usek: false,
           ks: 100,
           ks0: 0,
           gr: false,
           pollp: true,
           value: -200,
           desc: 'AO',
           kh0: 0,
           address: '1321',
           fcr: '3',
           useactions: false,
           kh: 100,
           nofb: false,
           unitid: 1,
           calc_outfn: [Function: anonymous],
           command: 'set' } ] }
    29.02 13:49:08.687 modbus1: Command to send: [ { chan: 'T.Antizam.Ku',
        id: 'T.Antizam.Ku',
        vartype: 'int16be',
        usek: false,
        ks: 100,
        ks0: 0,
        gr: false,
        pollp: true,
        value: -200,
        desc: 'AO',
        kh0: 0,
        address: 1321,
        fcr: '3',
        useactions: false,
        kh: 100,
        nofb: false,
        unitid: 1,
        command: 'set' },
      64,
      65,
      66,
      67,
      68,
      69,
      70,
      71 ]
    29.02 13:49:08.839 modbus1: WRITE: unitId = 1, FC = 6, address = 1321 (0x529), value = -200
    29.02 13:49:08.839 modbus1: writeSingleRegister: address = 1321 (0x529), value = -200
    29.02 13:49:08.841 modbus1: ERROR: TypeError: "value" argument is out of bounds
        at checkInt (buffer.js:1176:11)
        at Buffer.writeUInt16BE (buffer.js:1245:5)
        at ModbusRTU.writeFC6 (/var/lib/intrahouse-c/plugins/modbus/node_modules/modbus-serial/index.js:607:9)
        at /var/lib/intrahouse-c/plugins/modbus/node_modules/modbus-serial/apis/promise.js:48:31
        at new Promise (<anonymous>)
        at ModbusRTU.converted [as writeRegister] (/var/lib/intrahouse-c/plugins/modbus/node_modules/modbus-serial/apis/promise.js:39:27)
        at Object.modbusWriteCommand (/var/lib/intrahouse-c/plugins/modbus/app.js:345:36)
        at Object.write (/var/lib/intrahouse-c/plugins/modbus/app.js:302:28)
        at Object.sendNext (/var/lib/intrahouse-c/plugins/modbus/app.js:379:18)
        at Object.read (/var/lib/intrahouse-c/plugins/modbus/app.js:248:18)
    29.02 13:49:08.842 modbus1: Write result: undefined
    


  • @Erik
    Спасибо за тестирование, действительно, есть проблема с записью отрицательных целых значений в библиотеке modbus-serial.
    В новой версии библиотеки эта проблема исправлена. Проверим у себя и на следующей неделе выпустим новый релиз плагина



  • This post is deleted!


  • Есть ли возможность сделать сценарий, стартующий при загрузке IH ( некий аналог RunOnce) ? Иногда бывает нужно "привести в порядок" контролируемые устройства после внезапной перезагрузки сервера.



  • @alesle Да, такая возможность есть.
    Нужно в сценарий включить функцию boot, которая должна вернуть результат true, чтобы сценарий запустился при старте сервера. Выполнение, как обычно, начнется с функции start().
    Если не будет триггеров (startOnChange), то сценарий больше запускаться не будет

    boot() {
        return true; // Всегда запускать при старте сервера
    },
    
    start() {
       //  Здесь скрипт, который нужно выполнить
    } 
    

    Эта возможность не документирована. Возможно, синтаксис изменится при доработке API сценариев.



  • Можно ли обьявить модуль (функцию), который будет доступен из всех сценариев?



  • Подскажите. Такая ситуация: есть внешние ролокасеты, при закате солнца они автоматически закрываются по сценарию, есть датчик движения на улице. Проблема: как в сценарии указать что бы actor (ролокасета) не опускалось если было движение за последных 30 минут для примера, что бы не остатся ночевать на заднем дворе)))).



  • 3 скрипта. 1 доп актуатор.

    1. По датчику движения присвоить значение 1 доп актуатору на 30 минут.
    2. ПО изменении доп актуатора (при изменении с 1 на 0) проверить время, если закат закрыть ролокассеты.
    3. По таймеру Когда закат - проверить, что доп актуатор не 1, и закрыть ролокассету.


  • @Erik а кусочек сценария можно? Такого раньше не делал)))



  • @alesle Пока такой возможности нет



  • в следующей версии не планируете?



  • @intrapro, кстати да! Такая возможность очень нужна! У меня 100500 сценариев и в них просто копипастом вставляю одни и те же функции. По идее можно ведь как-то хотя бы вручную сделать библиотеку функций и подключать ее в сценариях?



  • @alesle, @Alex_Jet
    Программисты сказали "Вполне законное требование" 😉



  • @intrahouse, в связи с этим добавил новый пункт в теме по развитию версии 5)). Вообще мне ваши программисты в какой-то задаче уже подсказывали как подключать внешние библиотеки. Сейчас нет возможности найти эту задачу.



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

    @Erik а кусочек сценария можно? Такого раньше не делал)))

    Первый такой

    /** 
    * @name признак движения 
    * @desc  
    * @version 4  
    */
    
    
    const Actor = Device("ActorA", "Признак движения");
    const Motion = Device("SensorD", "Датчик движения"); 
    
    // Запустим сценарий при сработке датчика движения,
    startOnChange([Motion], Motion.isOn());
    
    script({
        start() {
             Actor.on();
             // взводим таймер, чтобы отключить 
             this.startTimer("T1", 3600, "turnOff");       
            
            // Добавляем слушатель - следим за датчиком движения
            this.addListener(Motion, "onMotion");
        },
        
        onMotion() {
          // Если движение возобновилось - сбрасываем таймер
          if (Motion.isOn() )  {
            this.stopTimer("T1");
          }  
           // Если движение прекратилось - взводим таймер (после повторных движений)
          if (Motion.isOff() && this.timer.T1 == "off")  {
            this.startTimer("T1",  3600, "turnOff");
          }  
        },
       
        // Функция, которая сработает, когда таймер досчитает - отключаем признак движения и выходим
        turnOff() {
          Actor.off();
          this.exit(); // Здесь exit нужен, так как есть активные слушатели и сценарий сам не завершится
        }
    });
    
    

    Второй такой (запускаем на закате)

    /** 
    * @name признак движения 
    * @desc  
    * @version 4  
    */
    
    
    const Actor = Device("ActorA", "Признак движения");
    const Rol = Device("ActorA", "Ролкассета"); 
    
    script({
        start() {
             
     if (Actor.isOff()) {
    //пишите тут то, что хотите сделать с Rol)
    Rol.on();
    this.exit();
    },
    
     if (Actor.isOn()) {
             // взводим таймер, чтобы отключить 
             this.startTimer("T1", 3600, "turnOff");       
            
            // Добавляем слушатель - следим за признаком движения
            this.addListener(Actor, "onActor");
        },
        
        onActor() {
           // Если признак движения отключился, закрываем Ролкассету
          if (Actor.isOff())  {
            Rol.on();
             this.exit();
         }  
        },
       
        // Функция, которая сработает, когда таймер досчитает - закрываем Ролкассету и выходим
        turnOff() {
          Rol.on();
          this.exit();
        }
    }
    });
    
    


  • Подскажите, пожалуйста.
    Есть датчик универсальный аналоговый. Привязан к датчику 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)) {
    ...
    }
    

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


Log in to reply