Сценарии - новая версия 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.
    В новой версии библиотеки эта проблема исправлена. Проверим у себя и на следующей неделе выпустим новый релиз плагина



  • Это сообщение удалено!


  • Есть ли возможность сделать сценарий, стартующий при загрузке 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'));
    не работает. В ошибках рабочего сценария пишет, что функция не определена. Если убрать условие отслеживания состояния, то сценарий отрабатывает по изменению значения каждую минуту. Хотел сократить число запусков. Подскажите, что не так


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