Сценарии в intraHouse Cherry



  • @Alex_Jet:

    Огромное спасибо за столь развернутый ликбез по теме сценариев. Надеюсь, это понадобится не только мне, но и другим пользователям.

    Вам спасибо за желание докопаться до сути 🙂

    Действительно, документации у нас не хватает. Надеюсь, скоро соберем все и выложим в Wiki.

    Успешного внедрения!



  • Дальше настраиваю сервер. Надо сделать сценарии для отопления "Эконом", "День", "Ночь".

    По сути это изменение уставок температуры у датчиков, у которых есть уставки.

    Как их менять "на лету"? Делаем сценарий без каких-либо триггеров и привязываем их к нужным кнопкам?

    А в сценарии прописываем типа:

    const script = {
        start() {
          const temp = 25;
          this.do(temp_guest.defval, temp);
        } 
    };
    
    

    В Berry было удобно, что значение для каждого режима сохранялось, когда пользователь сам настраивал температуру. В Cherry так получится сделать?

    PS: если делаешь шаг шкалы 0,5, то это выполняется только если менять уставку + и -. Если двигать ползунок, то шаг = 1.



  • Не дождался ответа - разобрался сам. Надо сделать так:

    this.assign(temp_guest, "defval", temp);
    
    

    Остается вопрос №2:
    @Alex_Jet:

    В Berry было удобно, что значение для каждого режима сохранялось, когда пользователь сам настраивал температуру. В Cherry так получится сделать?

    И еще вопрос - можно как-то в цикле перебрать сами устройства (ST_HEATING1_0x)???



  • @intrapro:

    Вам спасибо за желание докопаться до сути 🙂

    В предыдущих постах снова задал кучу вопросов - чтобы они не потерялись процитировал Вас.

    Сделал скрипт для имитации изменения значений аналоговых сенсоров:

    /** 
    * @name Эмуляция изменения температуры  
    * @desc  
    */
    
    const actor = Device("ActorD", "Актуатор", [
      {"name":"porog_0", "note":"Установить по on", "type":"number", "val":25},
      {"name":"porog_1", "note":"Установить по off", "type":"number", "val":0}
      ]);
    
    const sensor = Device("SensorA", "Сенсор");
    
    const script = {
        check() {
            return (actor.dval || !actor.dval);
        },
    
        start() {
          //const temp = 0;
          this.assign(sensor, "aval", (actor.dval) ?  actor.porog_1 : actor.porog_0);
        } 
    };
    
    

    Отвязал сенсор от канала контроллера, но изменения значения в вебе не происходит. В журнале сенсора вот такое:
    Сценарии_Изменение_значения_аналогового_сенсора_Ошибка.png



  • @Alex_Jet:

    Сделал скрипт для имитации изменения значений аналоговых сенсоров:

    Отвязал сенсор от канала контроллера, но изменения значения в вебе не происходит. В журнале сенсора вот такое:

    Скрипт рабочий. Скорее всего, значение не принимается, так как для датчика температуры установлен диапазон Min-Max и флаги:

    -Не принимать значения вне диапазона

    -Устанавливать ошибку при выходе из диапазона.

    И диапазон не включает 0-10
    Настройка_аналогового_датчика.png

    Другие вопросы не такие простые, отвечу позже. Встроенного решения, как в Berry, нет.

    А журнал в последнем релизе более симпатичный 😉
    assign_aval.png



  • @intrapro:

    Скрипт рабочий. Скорее всего, значение не принимается, так как для датчика температуры установлен диапазон Min-Max и флаги:

    -Не принимать значения вне диапазона

    -Устанавливать ошибку при выходе из диапазона.

    И диапазон не включает 0-10

    Да, Вы были правы! Я снова с просьбами о помощи:)

    1. Бьюсь со сценарием включения/отключения актюатора по аналоговому датчику температуры (эмулирую значения 24,8 и 25,2; уставка температуры 25, гистерезис 0,1). Не могу побороть проблему - при понижении температуры актюатор включается, а при повышении - не выключается! Скрипт:

    /** 
    * @name Актюатор ТП по датчику температуры  
    * @desc Сценарий работает при включеном режиме АВТО у актюатора
    *   При увеличении температуры выше целевого значения на величину гистерезиса актюатор включается, 
    *   при уменьшении температуры ниже целевого значения на величину гистерезиса - выключается.
    *   В качестве целевого значения берется уставка с датчика температуры (dt.defval)
    *   В качестве гистерезиса берется пользовательская настройка актюатора (act.hist)
    */
    
    const act = Device("ActorD", "Актюатор ТП", [
      {"name":"hist", "note":"Гистерезис включения/отключения актюатора, °C", "type":"number", "val":0.1}
      ]);
    
    const dt = Device("SensorA", "Датчик температуры");
    
    const script = {
        check() {
          return act.auto && ( !act.dval&&(dt.aval <= dt.defval-act.hist) || act.dval&&(dt.aval >= dt.defval+act.hist) );
        },
    
        start() {
          if(!act.dval) {
            this.do(act, "on");
          }
          else {
            this.do(act, "off");
          }
        }
    };
    
    

    Лог отладчика - почему во втором случае Check выдает false - я не понимаю!

    24.09 11:51:37.416 S1(ACTOR_HEATING1_01,ST_HEATING1_01) Check(ST_HEATING1_01) => true
    24.09 11:51:37.416 S1(ACTOR_HEATING1_01,ST_HEATING1_01) Started
    24.09 11:51:37.417 S1(ACTOR_HEATING1_01,ST_HEATING1_01) do ACTOR_HEATING1_01 on 
    24.09 11:51:37.418 S1(ACTOR_HEATING1_01,ST_HEATING1_01) Stopped
    24.09 11:51:47.394 S1(ACTOR_HEATING1_01,ST_HEATING1_01) Check(ST_HEATING1_01) => false
    
    

    2. У меня актюаторы НО. Чтобы когнитивный диссонанс не устраивать в скриптах, я так понимаю, в соответствующих каналах плагина MegaD нужно активировать чек-бокс "Ивертировать выходное значение"?

    3. Еще что заметил - этот скрипт отключает режим АВТО у актюатора! Как сделать чтобы режим АВТО не отключался скриптом (кроме установки в свойствах актюатора 00:00:00 для включения/отключения режима АВТО)?

    4. И научите как же все-таки пользоваться логированием?
    @Alex_Jet:

    @intrapro:

    Для отладки (и записи в журнал) можно использовать this.log():

    Пока не разобрался как же использовать log. Что он будет логировать? - работу функций или в его тело нужно вставлять какие-то комментарии?



  • @Alex_Jet:

    Лог отладчика - почему во втором случае Check выдает false - я не понимаю!

    Еще что заметил - этот скрипт отключает режим АВТО у актюатора!

    Check выдает false именно потому, что режим АВТО при операции on/off отключается.

    @Alex_Jet:

    Как сделать чтобы режим АВТО не отключался скриптом (кроме установки в свойствах актюатора 00:00:00 для включения/отключения режима АВТО)?

    Нужно использовать команды aon/aoff (как в Berry)

    this.do(act, "aon");
    
    

    @Alex_Jet:

    И научите как же все-таки пользоваться логированием?

    Любая строка, сформированная по правилам JS, будет выведена в журнал пользователя и в отладчик тоже

    this.log( "Температура "+dt.aval+". Уставка "+dt.defval);
    
    


  • @intrapro:

    Check выдает false именно потому, что режим АВТО при операции on/off отключается.

    Я тоже так думал и поэтому вручную в настройках актюатора установил 00:00:00 чтобы АВТО режим не отключался!

    В итоге с помощью логирования сейчас вот такую ерунду выяснил:

    24.09 13:34:47.890 S1(ACTOR_HEATING1_01,ST_HEATING1_01) log: Act.auto - 1; Act.dval - 0; Dt.aval = 24.8; Porog = 24.9
    24.09 13:34:47.895 S1(ACTOR_HEATING1_01,ST_HEATING1_01) Check(ST_HEATING1_01) => true
    24.09 13:34:47.895 S1(ACTOR_HEATING1_01,ST_HEATING1_01) Started
    24.09 13:34:47.896 S1(ACTOR_HEATING1_01,ST_HEATING1_01) do ACTOR_HEATING1_01 aon 
    24.09 13:34:47.897 S1(ACTOR_HEATING1_01,ST_HEATING1_01) Stopped
    24.09 13:35:05.407 S1(ACTOR_HEATING1_01,ST_HEATING1_01) log: Act.auto - 1; Act.dval - 1; Dt.aval = 25.2; Porog = 25.000.1
    24.09 13:35:05.412 S1(ACTOR_HEATING1_01,ST_HEATING1_01) Check(ST_HEATING1_01) => false
    
    

    Почему во втором случае Porog (dt.defval + act.hist) = 25.000.1? Почему не суммируется?



  • @Alex_Jet:

    Почему во втором случае Porog (dt.defval + act.hist) = 25.000.1? Почему не суммируется?

    JavaScript, он такой. Исправим у себя преобразование типов параметров сценария, недоглядели 😞

    Вам же достаточно сделать Number(dt.defval)

    Ну, вы наверное уже и сами догадались 🙂



  • @intrapro:

    @Alex_Jet:

    Почему во втором случае Porog (dt.defval + act.hist) = 25.000.1? Почему не суммируется?

    JavaScript, он такой. Исправим у себя преобразование типов параметров сценария, недоглядели 😞

    Вам же достаточно сделать Number(dt.defval)

    Ну, вы наверное уже и сами догадались 🙂

    У меня не такой огромный опыт в JS как у Вас. Поэтому для меня это было загадкой.

    Да, теперь работает. Единственный вопрос еще: как правильнее и чем это грозит:

    1. Проверка в check "короткого" условия return act.auto && dt.aval с последующей проверкой условий в start

    2. Проверка в check "длинного" условия return act.auto && dt.aval ( !act.dval&&(dt.aval <= dt.defval - act.hist) || act.dval&&(dt.aval >= dt.defval + act.hist) )

    PS: расскажите в теме про CCTV про видеоалерты - есть ли уже такая возможность? и как настраивать.



  • @Alex_Jet:

    Единственный вопрос еще: как правильнее и чем это грозит:

    1. Проверка в check "короткого" условия return act.auto && dt.aval с последующей проверкой условий в start

    2. Проверка в check "длинного" условия return act.auto && dt.aval ( !act.dval&&(dt.aval <= dt.defval - act.hist) || act.dval&&(dt.aval >= dt.defval + act.hist) )

    Да ничем не грозит, дело вкуса.

    Второй вариант предпочтительнее, т к :

    1. Меньше количество операций сравнения.

    Условные выражения в JS работают до первого ложного условия - т е если act.auto=0 - больше ничего проверяться не будет в обоих вариантах, хотя на вид условие по 2 варианту длинное.

    А если act.auto =1, то по 1 варианту сначала будет проверка dt.aval в check (Вам пришлось вставить, чтобы датчик был триггером), а потом будет проверка в start

    2. Меньше будет зафиксировано запусков сценария.

    По 1 варианту запуск будет фиксироваться при каждом изменении тем-ры, а если она у вас с десятыми (или даже с сотыми), то количество запусков быстро перевалит за 1000. А на фиксацию запуска сценария также тратятся ресурсы.

    По 2 варианту запуск сценария означает, что выполняется регулирование.

    Но работать будут оба варианта.

    @Alex_Jet:

    PS: расскажите в теме про CCTV про видеоалерты - есть ли уже такая возможность? и как настраивать.

    Запланировано, но пока не реализовано



  • @intrapro:

    Да ничем не грозит, дело вкуса.

    Ок, понятно. По актюаторам еще можно комментарий?
    @Alex_Jet:

    2. У меня актюаторы НО. Чтобы когнитивный диссонанс не устраивать в скриптах, я так понимаю, в соответствующих каналах плагина MegaD нужно активировать чек-бокс "Ивертировать выходное значение"?



  • @Alex_Jet:

    У меня актюаторы НО. Чтобы когнитивный диссонанс не устраивать в скриптах, я так понимаю, в соответствующих каналах плагина MegaD нужно активировать чек-бокс "Ивертировать выходное значение"?

    Да, должно работать (примерно как было в Berry)



  • @Alex_Jet:

    @intrapro:

    Можно еще проще - привязать бинарный актуатор, а интерактивные операции для него отключить

    В принципе эта идея сработала. При поднесении нужного ключа к считывателю актуатор меняет свое состояние. Отталкиваясь от его состояния можно написать сценарий установки/снятия с охраны. Единственный неопределенный момент в том, что когда MegaD опрашиваем командой cmd=all, то канал, соответствующий считывателю находится в неопределенном состоянии (ранее писал, что не верно под неопределенным состоянием считать 0). Возникает вопрос - после перезагрузки MegaD в каком состоянии окажется привязанный к этому каналу актуатор (ну или сенсор, если добавите ему обработку toggle). Или все же это правильно - считать за 0/OFF неопределенное состояние порта?

    Написал сценарий постановки дома на охрану. Button - это актюатор, который привязан ко входу MegaD, к которому подключен считыватель. Кроме этого, из этого устройства сделан индикатор постановки на охрану в строке состояния и две кнопки "Постановка/Снятие с охраны" (для одной в свойствах выбрано on, для другой - off). Lamp - это сигнальная лампа (загорается при постановке), Ring - это сирена.

    const Button = DeviceT("ACTOR_SECURITY_SYS01");
    const Lamp = Device("ACTOR_SECURITY_SYS02");
    const Ring = Device("ACTOR_SECURITY_SYS03");
    
    const script = {
        start() {
          this.log(Button.name+ "=" +Button.dval);
    
          if(Button.dval) {
            this.do(Lamp, "on");  //Включаем лампу
            this.do(Ring, "on");  //На секунду срабатывает сирена
            this.startTimer("T1", 0.1, "ringOff");
          }
          else {
            this.do(Lamp, "off");  //Выключаем лампу
            this.do(Ring, "on");  //На секунду срабатывает сирена
            this.startTimer("T1", 0.1, "ringOff");
          }
    
        },
    
        // Функция, которая сработает, когда таймер досчитает - отключаем и выходим
        ringOff() {
          this.do(Ring, "off");
          this.exit();
        }
    };
    
    

    Суть в том, что при сработке считывателя все работает хорошо (актюатор меняет свое состояние и скрипт все верно отрабатывает). А вот при нажатии кнопок работает не верно - нажимаю кнопку "Поставить на охрану" (on) индикатор охраны становится активным, но реле сигнальном лампы не срабатывает, а в отладчике скрипта видно, что актюатор почему-то не "встал":

    27.10 23:52:44.905 Trigger ACTOR_SECURITY_SYS01
    27.10 23:52:44.905 Started
    27.10 23:52:44.906 log: Актуатор постановки на охрану=0
    27.10 23:52:44.912 do ACTOR_SECURITY_SYS02 off 
    27.10 23:52:44.916 do ACTOR_SECURITY_SYS03 on 
    27.10 23:52:44.918 start timer T1 for 0.1 sek
    27.10 23:52:45.026 Done timer T1
    27.10 23:52:45.026 exec function ringOff
    27.10 23:52:45.027 do ACTOR_SECURITY_SYS03 off 
    27.10 23:52:45.029 exit
    27.10 23:52:45.029 Stopped
    
    

    Не могу понять почему так происходит? Надо таймер взводить перед проверкой состояния актюатора?

    Up1: методом итераций (сначало сделал таймер на 0,1 секунду с переходом в main), потом чтобы при повторном нажатии той же кнопки (когда взято под охрану, но еще раз нажимают кнопку "Взять под охрану") не срабатывала сирена решил проверять совпадает текущее значение актуатора с предыдущем, потом судя по логам работы решил убрать таймер. И получилось вот что:

    const Button = DeviceT("ACTOR_SECURITY_SYS01"); //Актуатор постановки на охрану
    const Lamp = Device("ACTOR_SECURITY_SYS02");    //Сигнальная лампа
    const Ring = Device("ACTOR_SECURITY_SYS03");    //Сирена
    var Status;
    
    const script = {
        start() {
          //this.log(Button.name+ " = " +Button.dval);
    
          this.main();
          Status = Button.dval;
        },
    
        // Основная функция постановки на охрану
        main() {
          //this.log(Button.name+ " = " +Button.dval);
    
          //Если предыдущее состояние актуатора совпадает с текущим, то выходим.
          if(Status != Button.dval) {
            if(Button.dval) this.do(Lamp, "on");    //Включаем лампу
            else            this.do(Lamp, "off");   //Выключаем лампу
            this.do(Ring, "on");  //Срабатывает сирена
            this.startTimer("T1", 0.1, "ringOff");
          }
        },
    
        // Функция отключения сирены с выходом из скрипта
        ringOff() {
          this.do(Ring, "off");
          this.exit();
        }
    };
    
    

    Парадокс в том, что если исключить Status = Button.dval; или перенести до this.main(); то ничего не работает. А именно в такой последовательности - работает. Однако моя логика не понимает в чем суть…



  • @Alex_Jet:

    Написал сценарий постановки дома на охрану. Button - это актюатор, который привязан ко входу MegaD, к которому подключен считыватель. Кроме этого, из этого устройства сделан индикатор постановки на охрану в строке состояния и две кнопки "Постановка/Снятие с охраны" (для одной в свойствах выбрано on, для другой - off)…..

    А канал считывателя MegaD отрабатывается как toggle?

    Думаю, проблема в том, что у вас устройство Button, с одной стороны - псевдоактуатор с привязкой к считывателю, с другой - его же вы используете как виртуальный актуатор для постановки/снятия. Но фактически у вас выход не переключается, поэтому состояние может не совпадать с ожидаемым.

    Можете посмотреть журнал устройства (при длинном нажатии).

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

    Выход - создать отдельный виртуальный актуатор Постановка/Снятие (Guard, например).

    Он выводится на индикацию, он переключается кнопками. По его событиям включается сигнальная лампа и вообще все, что нужно сделать при постановке (снятии). Его состояние вы можете учитывать в других сценариях (датчики, герконы на охране и т д, ну вы знаете 🙂

    Дополнительно, как я понимаю, вы хотите реализовать Постановку (и Снятие?) при сработке считывателя. Т е это триггер, который должен переключить Guard . Так это и надо реализовать - отдельный сценарий, который просто переключает Guard по считывателю (по сути, как кнопка)



  • @intrapro:

    @Alex_Jet:

    Написал сценарий постановки дома на охрану. Button - это актюатор, который привязан ко входу MegaD, к которому подключен считыватель. Кроме этого, из этого устройства сделан индикатор постановки на охрану в строке состояния и две кнопки "Постановка/Снятие с охраны" (для одной в свойствах выбрано on, для другой - off)…..

    А канал считывателя MegaD отрабатывается как toggle?

    Думаю, проблема в том, что у вас устройство Button, с одной стороны - псевдоактуатор с привязкой к считывателю, с другой - его же вы используете как виртуальный актуатор для постановки/снятия. Но фактически у вас выход не переключается, поэтому состояние может не совпадать с ожидаемым.

    Можете посмотреть журнал устройства (при длинном нажатии).

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

    Выход - создать отдельный виртуальный актуатор Постановка/Снятие (Guard, например).

    Он выводится на индикацию, он переключается кнопками. По его событиям включается сигнальная лампа и вообще все, что нужно сделать при постановке (снятии). Его состояние вы можете учитывать в других сценариях (датчики, герконы на охране и т д, ну вы знаете 🙂

    Дополнительно, как я понимаю, вы хотите реализовать Постановку (и Снятие?) при сработке считывателя. Т е это триггер, который должен переключить Guard . Так это и надо реализовать - отдельный сценарий, который просто переключает Guard по считывателю (по сути, как кнопка)

    Да, канал считывателя отрабатывается как toggle.

    Вообще я замечал, что если актуатор привязан к каналу и канал недоступен (плагин не включен, MegaD недоступна), то при переключении актуатора в вебе его состояние не меняется. Тут же канал доступен, актуатор свое состояние в вебе меняет, а логическое состояние изменяется только после повторного нажатия кнопки. Парадокс в том, что мой последний скрипт работает так как задумано (и от устройств-кнопок и от считывателя), но при этом сам скрипт вообще не логичен…

    По поводу дополнительного сценария - у меня сейчас уже порядка 30 различных скриптов, поэтому дополнительных плодить не хотел. И именно поэтому ранее вносил предложение - добавить в скриптах признак системы.

    В общем попробую ваше предложение осуществить.



  • Сделал новый актуатор не привязанный к каналам, переделал скрипт - вечером посмотрю как работает со считывателем (с "виртуальным" актуатором, судя по отладчикам, проблем нет). Вопрос - чтобы состояние "виртуального" актуатора оставалось актуальным даже после выключения/включения сервера надо изменение его состояния записывать в БД? Или его последнее состояние храниться в json и даже после жесткого ребута будет актуальным?

    PS: для входов состояние toggle будете определять?



  • @Alex_Jet:

    Вопрос - чтобы состояние "виртуального" актуатора оставалось актуальным даже после выключения/включения сервера надо изменение его состояния записывать в БД? Или его последнее состояние храниться в json и даже после жесткого ребута будет актуальным?

    Нет, в БД писать не надо. Да, будет сохраняться.

    Гарантированный интервал сохранения на диск 10 сек (при жестком ребуте есть вероятность потери состояний, изменившихся за последние 10 сек)

    @Alex_Jet:

    PS: для входов состояние toggle будете определять?

    Не совсем понятен вопрос. toggle - это операция. Состояние - результат выполнения, зависит от предыдущего состояния.

    Поэтому для входов определять toggle считают неверным. Мы же реальное состояние с входа только получаем, повлиять на него не можем, но можем сильно запутаться 🙂

    Для канала считывателя, если считаете, что вам удобнее toggle - определите его как выход



  • @intrapro:

    Для канала считывателя, если считаете, что вам удобнее toggle - определите его как выход

    ОК, понятно. А как в скрипте сделать toggle для актуатора состояния сигнализации? То есть при любом изменении reader изменить состояние Button на противоположное? Что-то не могу догадаться…



  • @Alex_Jet:

    А как в скрипте сделать toggle для актуатора состояния сигнализации? То есть при любом изменении reader изменить состояние Button на противоположное? Что-то не могу догадаться…

    Вы же все уже сделали - канал привязали к актуатору Button c операцией toggle. Он сам меняет состояние по считывателю.

    Что вам осталось сделать - по триггеру Button переключать Guard


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