Помогите пожалуйста с подбором и настройкой оборудования для теплиц

Сегодня посмотрю, воспроизведу.

Спасибо большое

Вникаю. Не забыл про вас.

Приятно. Спасибо)

Там для диммирования я применял формулу перевода, чтобы выставлять не фактическую мощность на выходе модуля, а процент. К примеру когда человек задаёт 20%, то на выходе модуля будет 2000. И я переделал привязку установки облучённости к фактическому уровню облучённости, чтобы было проще привязать изменения. то есть фактическая облучённость будет постоянно скакать на 100 единиц, но при этом реагировать на изменение установки облучённости (по моему раньше была проблема, что при изменении установки облучённости, фактическая облучённость не менялась). Возможно это не самое оптимальное решение, но оно работает)

Screenshot_2

Нашел пару ошибок, попробуйте:

//light_test_w.js 
//'use strict';
var grow_box = "test_w"; // CHANGE_ME! имя устройства. Выводится в заголовок окна и служит для разделения устройств
log.info("light_"+grow_box+"START######################"); //Это лог.

var dimmer_light = "wb-mao4_61/Channel 4"; // CHANGE_ME! устройство-диммер То есть строка, которая определяет куда писать изменения мощности.
var dimmer_zeroValue = 0; //"0" диммера
var dimmer_maxValue = 10000; //100% диммера

var pump_wet = "wb-mr6cu_22/K2"; // Устройство помпа
var sensor_wet = "wb-mai2-mini_11/Current input 1 (mA)"; // текущая влажность, устройство

var dimmer_relay = "wb-mr6cu_22/K3"; //CHANGE_ME! устройство-реле питания диммера (доработка, используемй диммер подтягивает свой вход к VCC)

var ps = new PersistentStorage("storage_"+grow_box, {global: true});// Определим объект-хранилище.

var setpointwet = ps["set_Point_Wet"]; //требуемая влажность
var wetTime = ps["wetTime"]; //время (длительность) полива
var sunraiseStartTime; //Время начала "рассвета"
var sunraiseStopTime; //Время конца "рассвета"
var sunsetStartTime;//Время начала "заката"
var sunsetStopTime; //Длительность "заката"
var light_increment = 0; //Глобальная для хранения приращения освещенности
var setPointLight = (((ps["light_setpoint"])-1)*100).toString(); // уставка освещенности
//var dimmer_increment = (dimmer_maxValue-dimmer_zeroValue)/400; //увеличение освещения в цикл расчетное на 0.25%
var dimmer_increment = 100; //увеличение освещения в цикл 1%
setTimeVariable();

//Проверим на null переменную из хранилища 
//и дадим какое-то значение, на случай "нового" скрипта.

if (!ps["sun_stop_time"]){
  log.info("sun_stop_time undefined")
  ps["sun_stop_time"]="18:00"
}


//Элементы виртуального устройства
//управления
var deviceCells = { 
  "Lamp power set" : {
    type : "range",
    value : dimmer_zeroValue,
    min : dimmer_zeroValue,
    max : dimmer_maxValue
  },
  //Начало рассвета hh:mm
  "Sunraise (start) time": {
    type: "text",
    readonly: false,
    value: ps["sun_start_time"],
  },
  //Длительность рассвета
  "Sunraise duration": {
    type: "text",
    readonly: false,
    value: ps["sun_start_duration"],
  },
  //Начало заката hh:mm
  "Sunset (stop) time": {
    type: "text",
    readonly: false,
    value: ps["sun_stop_time"],
  },
  //Длительность заката
  "Sunset duration": {
    type: "text",
    readonly: false,
    value: ps["sun_stop_duration"],
  },
  "Light SetPoint": {
    type: "value",
    readonly: false,
    value: ps["light_setpoint"]
  },

  //Влажность включения
  "Set Point Wet": {
    type: "value",
    readonly: false,
    value: ps["set_Point_Wet"],
  },
  //Время полива
  "Wet Time": {
    type: "text",
    readonly: false,
    value: ps["wetTime"],
  },
  pumpwork : {
          type : "switch",
          value : false,
  }, 
  sunraiseProcess : {
          type : "switch",
          value : false,
  },   
  sunsetProcess : {
          type : "switch",
          value : false,
  },
  dayProcess : {
          type : "switch",
          value : false,
  },
};



//Создадим виртуальное устройство и добавим в него элементы 
  defineVirtualDevice("light_"+grow_box, {
    title:"Light of "+grow_box,
    cells: deviceCells
  });

defineRule("Set Point Wet change", { //название правила 
whenChanged: "light_"+grow_box+"/Set Point Wet", //при изменении поля желаемой влажности запишем его в хранилище
  then: function (newValue, devName, cellName) { //выполняй следующие действия
    log.info("light_"+grow_box+"/Set Point Wet", newValue); //Это лог. Он попадает в /var/log/messages
    ps["set_Point_Wet"] = newValue;
    setpointwet = newValue;
  }
});

defineRule("Wet Time change", { //название правила 
whenChanged: "light_"+grow_box+"/Wet Time", //при изменении поля желаемого времени полива запишем его в хранилище
  then: function (newValue, devName, cellName) { //выполняй следующие действия
    log.info("light_"+grow_box+"/Wet Time", newValue); //Это лог. Он попадает в /var/log/messages
    ps["wetTime"] = newValue;
    wetTime = newValue;
    setTimeVariable();
  }
});

defineRule("Sunraise start time change", { //название правила 
whenChanged: "light_"+grow_box+"/Sunraise (start) time", //при изменении поля времени начала рассвета запишем его в хранилище
  then: function (newValue, devName, cellName) { //выполняй следующие действия
    log.info("light_"+grow_box+"/Sunraise start time ", newValue); //Это лог. Он попадает в /var/log/messages
    ps["sun_start_time"] = newValue;
    setTimeVariable();
  }
});

defineRule("Sunraise duration change", { //название правила 
whenChanged: "light_"+grow_box+"/Sunraise duration", //при изменении поля времени рассвета запишем его в хранилище
  then: function (newValue, devName, cellName) { //выполняй следующие действия
    log.info("light_"+grow_box+"/Sunraise duration", newValue); //Это лог. Он попадает в /var/log/messages
    ps["sun_start_duration"] = newValue;
    setTimeVariable();
  }
});

defineRule("Sunset start time change", { //название правила 
whenChanged: "light_"+grow_box+"/Sunset (stop) time", //при изменении поля времени начала ЗАКАТА запишем его в хранилище
  then: function (newValue, devName, cellName) { //выполняй следующие действия
    log.info("light_"+grow_box+"/Sunset (stop) time ", newValue); //Это лог. Он попадает в /var/log/messages
    ps["sun_stop_time"] = newValue;
    setTimeVariable();
  }
});

defineRule("Sunset duration change", { //название правила 
whenChanged: "light_"+grow_box+"/Sunset duration", //при изменении поля времени заката запишем его в хранилище
  then: function (newValue, devName, cellName) { //выполняй следующие действия
    log.info("light_"+grow_box+"/Sunset duration", newValue); //Это лог. Он попадает в /var/log/messages
    ps["sun_stop_duration"] = newValue;
    setTimeVariable();
  }
});

defineRule("Light SetPoint change", { //название правила 
whenChanged: "light_"+grow_box+"/Light SetPoint", //при уставки желаемой освещенности -запишем в хранилище
  then: function (newValue, devName, cellName) { //выполняй следующие действия
    log.info("light_"+grow_box+"/light_setpoint ", newValue); //Это лог. Он попадает в /var/log/messages
    ps["light_setpoint"] = ((newValue-1)*100).toString();
    setPointLight = ((newValue-1)*100).toString();
  }
});
defineRule("dayProcess change", { //название правила 
whenChanged: "light_"+grow_box+"/dayProcess", // Для режима "День"
  then: function (newValue, devName, cellName) { //выполняй следующие действия
    if (newValue){ //Включаем "день"
    //log.info("light_"+grow_box+"/light_setpoint ", newValue); //Это лог. Он попадает в /var/log/messages
      dev["light_"+grow_box+"/sunraiseProcess"] = false; //Выключаем "рассвет" Таймер остановит правило "SunRaise_starter"
      //dev["light_"+grow_box+"/sunsetProcess"] = false; //Выключаем "закат" Таймер остановит правило "SunSet_starter"
      setPointLight = Number(ps["light_setpoint"]); // уставка освещенности
    }else{
      //dev[dimmer_light] = dimmer_zeroValue;
    }
  }
});

//* Статический сценарий

defineRule("start change", { //название правила 
whenChanged: "light_"+grow_box+"/sunraiseProcess", //При изменении флага "рассвет" - установим значения виртуального устройства.
  then: function (newValue, devName, cellName) { //выполняй следующие действия
    if ((dev["light_"+grow_box]["sunraiseProcess"]==true)){// если сейчас нужен свет
      newValue = Number(newValue); //Приведем к числу
      if (newValue>setPointLight) { // Если текущая освещенность 0
        //log.info("light_"+grow_box+"Light_measured BIG",newValue);
        if (dev[dimmer_light]<dimmer_maxValue){
          dev[dimmer_light] += dimmer_increment;
        }
      }
      dev["light_"+grow_box+"/Lamp power set"] = dev[dimmer_light];
    }
  }
});

defineRule("start_sunraise change", { //название правила 
whenChanged: "light_"+grow_box+"/sunraiseProcess", //При изменении флага "рассвет" - установим значения виртуального устройства.
  then: function (newValue, devName, cellName) { //выполняй следующие действия
    dev["light_"+grow_box]["dimmer_light"] = newValue;
    if ((dev["light_"+grow_box]["sunraiseProcess"]==true)){// если сейчас нужен свет
      newValue = Number(newValue); //Приведем к числу
        if (dev[dimmer_light]=0){
          dev[dimmer_light] += dimmer_increment;
      }
      dev["light_"+grow_box+"/Lamp power set"] = dev[dimmer_light];
    }
  }
});
defineRule("start_sunset change", { //название правила 
whenChanged: "light_"+grow_box+"/sunsetProcess", //При изменении флага "закат" - установим значения виртуального устройства.
  then: function (newValue, devName, cellName) { //выполняй следующие действия
    dev["light_"+grow_box]["dimmer_light"] = newValue;
    if ((dev["light_"+grow_box]["sunraiseProcess"]==true)||(dev["light_"+grow_box]["dayProcess"]==true)||(dev["light_"+grow_box]["sunsetProcess"]==true)){// если сейчас нужен свет
      newValue = Number(newValue); //Приведем к числу
      if (newValue>setPointLight) { // Если текущая освещенность больше уставки
        //log.info("light_"+grow_box+"Light_measured BIG",newValue);
        if (dev[dimmer_light]>dimmer_zeroValue){
          dev[dimmer_light] -= dimmer_increment;
        }
      } else{ // если меньше
        //log.info("light_"+grow_box+"Light_measured LOW",newValue);
        if (dev[dimmer_light]<dimmer_maxValue){
          dev[dimmer_light] += dimmer_increment;
        }
      }
      dev["light_"+grow_box+"/Lamp power set"] = dev[dimmer_light];
    }
  }
});
defineRule("start_day change", { //название правила 
whenChanged: dimmer_light, //При изменении флага "день" - установим значения виртуального устройства.
  then: function (newValue, devName, cellName) { //выполняй следующие действия
    dev["light_"+grow_box]["dimmer_light"] = newValue;
    if ((dev["light_"+grow_box]["sunraiseProcess"]==true)||(dev["light_"+grow_box]["dayProcess"]==true)||(dev["light_"+grow_box]["sunsetProcess"]==true)){// если сейчас нужен свет
      newValue = Number(newValue); //Приведем к числу
      if (newValue>setPointLight) { // Если текущая освещенность больше уставки
        //log.info("light_"+grow_box+"Light_measured BIG",newValue);
        if (dev[dimmer_light]>dimmer_zeroValue){
          dev[dimmer_light] -= dimmer_increment;
        }
      } else{ // если меньше
        //log.info("light_"+grow_box+"Light_measured LOW",newValue);
        if (dev[dimmer_light]<dimmer_maxValue){
          dev[dimmer_light] += dimmer_increment;
        }
      }
      dev["light_"+grow_box+"/Lamp power set"] = dev[dimmer_light];
    }
  }
});
defineRule("dayProcess change on", { //название правила 
whenChanged: "light_"+grow_box+"/sunraiseProcess", // Для режима "День"
  then: function (newValue, devName, cellName) { //выполняй следующие действия
    if ((dev["light_"+grow_box]["sunraiseProcess"]==false)){ //если рассвет выключается
      dev["light_"+grow_box+"/dayProcess"] = true; // то "день" включается
    }
  }
});

//* Окончание статического сценария
//* дополнение для полива

timerId = null;
defineRule("WET change", { //название правила 
whenChanged: sensor_wet, //При изменении измеренной влажности - определим необходимость полива.
  then: function (newValue, devName, cellName) { //выполняй следующие действия
    newValue = Number(newValue); //Приведем к числу
    dev["light_"+grow_box]["sensor_wet"] = newValue;
    if ((dev["light_"+grow_box]["dayProcess"])&&(newValue<setpointwet)){//День и увлажнение требуется
      if (!timerId){ //Если таймер еще не запущен
              dev["light_"+grow_box+"/pumpwork"] = true; //Включаем насос
        timerId = setTimeout(function () { //Начинаем описывать таймер
        dev["light_"+grow_box+"/pumpwork"] = false; //ВЫключаем насос   (тут можно описать требуемое действие)
            timerId = null; //Сбрасываем идентификатор отработавшего таймера
          }, wetTime);
      }
    }
  }
});

defineRule("WetProcess change", { //название правила 
whenChanged: "light_"+grow_box+"/pumpwork", // Отслеживаем состояние контрола, вся логика - в правиле выше
  then: function (newValue, devName, cellName) { //выполняй следующие действия
      dev[pump_wet] = newValue; // Помпа включается вместе с контролом.
  }
});

//* Окончание дополнения для полива

defineRule("cron minute timer", { //Просто задание, которое выполняется каждую минуту и взводит/опускает флаги "Рассвет", "Закат"
  when: cron("00 * * * * *"),
  then: function () {
    //log.info(grow_box, "cron timer executed! DEBUG ONLY.");
    d = new Date(); //Текущее время
    //sunraiseStartTime 
    if ((dev["light_"+grow_box]["sunraiseProcess"]==false) && (d > sunraiseStartTime) && (d<sunraiseStopTime)){
      log.info(grow_box, "cron timer executed! Sunraise process START", "sunraiseStartTime",sunraiseStartTime ,"sunraiseStopTime",sunraiseStopTime);
      dev["light_"+grow_box]["sunraiseProcess"] = true;
    }
    //sunsetStartTime
    if ((dev["light_"+grow_box]["sunsetProcess"]==false) && (d > sunsetStartTime) && (d<sunsetStopTime)){
      log.info(grow_box, "cron timer executed! SunSET process START", "sunsetStartTime",sunsetStartTime ,"sunsetStopTime",sunsetStopTime);
      dev["light_"+grow_box]["sunsetProcess"] = true;
    }
    //dayProcess
    if ((dev["light_"+grow_box]["dayProcess"]==false) && (d > sunraiseStopTime) && (d<sunsetStartTime)){
      log.info(grow_box, "cron timer executed! DAY process START","sunraiseStopTime",sunraiseStopTime,"sunsetStartTime",sunsetStartTime);
      dev["light_"+grow_box]["dayProcess"] = true;
    }
  }
});

defineRule("cron day timer", { //Просто задание, которое выполняется раз в сутки и меняет дату в переменных на текущую.
  when: cron("01 00 00 * * *"),
  then: function () {
    setTimeVariable();
  }
});

function string_to_time(srcString) { 
  //log.info("string_to_time_"+grow_box, srcString)
  var d = new Date();
  var datetime = new Date(d.getFullYear()+'-'+(d.getMonth()+1)+'-'+d.getDate()+'T' + srcString + 'Z');
  datetime.setMinutes(datetime.getMinutes() + datetime.getTimezoneOffset());//Приведем к локальному:
  return datetime; 
};


function setTimeVariable() { 
  sunraiseStartTime = string_to_time(ps["sun_start_time"]); //Время начала "рассвета"
  sunraiseStopTime = new Date(sunraiseStartTime);
  sunraiseStopTime.setMinutes(sunraiseStopTime.getMinutes() + parseInt(ps["sun_start_duration"])); //окончание "рассвета"
  sunsetStartTime = string_to_time(ps["sun_stop_time"]);//Время начала "заката"
  sunsetStopTime = new Date(sunsetStartTime);
  sunsetStopTime.setMinutes(sunsetStopTime.getMinutes() + parseInt(ps["sun_stop_duration"])); //окончание "заката"
};


defineRule("SunRaise_starter", { //название правила 
whenChanged: "light_"+grow_box+"/sunraiseProcess", //При изменении переуключателя "рассвет"
  then: function (newValue, devName, cellName) { //выполняй следующие действия
    log.info("light_"+grow_box+" sunraiseProcess function", newValue, devName, cellName); //Это лог.
    if (newValue){ //Запускаем "рассвет"
      dura = (sunraiseStopTime - sunraiseStartTime)/1000; //время в секундах
      setPointLight = Number(ps["light_setpoint"]); // уставка освещенности
      light_increment = setPointLight/dura; //увеличение освещенности в секунду расчетное
      setPointLight = 1;
	  log.info("light_"+grow_box+" sunraiseProcess", "dura", dura, "dimmer_increment", dimmer_increment); //Это лог.
      startTicker(grow_box+"raiseTicker", 1000); //Запуск таймера, отрабатывает раз в секунду.
    } else { //Останавливаем "рассвет"
      timers[grow_box+"raiseTicker"].stop(); 
      log.info("light_"+grow_box+"Ticker STOP sunraise");
    }
  }
});

defineRule("SunSet_starter", { //название правила 
whenChanged: "light_"+grow_box+"/sunsetProcess", //При изменении переуключателя "Закат"
  then: function (newValue, devName, cellName) { //выполняй следующие действия
    log.info("light_"+grow_box+" sunsetProcess function", newValue, devName, cellName); //Это лог.
    if (newValue){ //Запускаем "закат"
      dev["light_"+grow_box]["dayProcess"] = false;
      setPointLight = Number(ps["light_setpoint"]); // уставка освещенности
      dura = (sunsetStopTime - sunsetStartTime)/1000; //время в секундах
      light_increment = -(setPointLight)/dura; //уменьшение освещения в секунду расчетное. От уставки!
      //dev["light_"+grow_box+"/dayProcess"] = false; //Выключаем "день"
	  log.info("light_"+grow_box+" sunsetProcess", "dura", dura, "light_increment", light_increment, "setPointLight", setPointLight); //Это лог.
      startTicker(grow_box+"raiseTicker", 1000); //Запуск таймера, отрабатывает раз в секунду.
    } else { //Останавливаем "закат"
      timers[grow_box+"raiseTicker"].stop(); 
      log.info("light_"+grow_box+"Ticker STOP sunset");
      setPointLight = 0;
      dev[dimmer_light] = dimmer_zeroValue;
    }
  }
});


defineRule("handmadeSunTicker", { // Таймер плавного рассвета/заката
  when: function () { return timers[grow_box+"raiseTicker"].firing; },
  then: function () {
    setPointLight += light_increment;
    if (setPointLight>Number(ps["light_setpoint"])){
      log.info("light_"+grow_box+"raiseTicker STOP ON setPointLight");
      dev["light_"+grow_box+"/sunraiseProcess"] = false; //Выключаем "рассвет" Таймер остановит правило "SunRaise_starter"
    }
    if (setPointLight<0){
      log.info("light_"+grow_box+"setTicker STOP ON setPointLight");
      dev["light_"+grow_box+"/sunsetProcess"] = false; //Выключаем "закат" Таймер остановит правило "SunSet_starter"
    }
    if ((dev["light_"+grow_box+"/Lamp power set"]>dimmer_maxValue)||(dev["light_"+grow_box+"/Lamp power set"]<dimmer_zeroValue)){
      log.info("light_"+grow_box+"raiseTicker STOP ON Lamp power set");
      dev["light_"+grow_box+"/sunraiseProcess"] = false; //Выключаем "рассвет" Таймер остановит правило "SunRaise_starter"
      dev["light_"+grow_box+"/sunsetProcess"] = false; //Выключаем "закат" Таймер остановит правило "SunSet_starter"
    }
  }
});

Спасибо огромное за оптимизацию кода. Действительно смотрится очень круто. Полив включается относительно влажности, но по какой-то причине не отрабатывает таймер. Не отключается. я попробовал написать сторонний таймер по похожему примеру Выключение реле по таймеру но что-то не получилось. Может можете глянуть, в чём может быть дело? и хорошо было бы встроить какую-нибудь задержку времени, чтобы он не включался сразу после полива, а, к примеру, минут через 5. Спасибо

Так, сейчас проверю, таймер.
Нашел, час занял поиск, самая злая ошибка, типов.

//light_test_w.js 
//'use strict';
var grow_box = "test_w"; // CHANGE_ME! имя устройства. Выводится в заголовок окна и служит для разделения устройств
log.info("light_"+grow_box+"START######################"); //Это лог.

var dimmer_light = "wb-mao4_61/Channel 4"; // CHANGE_ME! устройство-диммер То есть строка, которая определяет куда писать изменения мощности.
var dimmer_zeroValue = 0; //"0" диммера
var dimmer_maxValue = 10000; //100% диммера

var pump_wet = "wb-mr6cu_22/K2"; // Устройство помпа
var sensor_wet = "wb-mai2-mini_11/Current input 1 (mA)"; // текущая влажность, устройство


var dimmer_relay = "wb-mr6cu_22/K3"; //CHANGE_ME! устройство-реле питания диммера (доработка, используемй диммер подтягивает свой вход к VCC)

var ps = new PersistentStorage("storage_"+grow_box, {global: true});// Определим объект-хранилище.

var setpointwet = ps["set_Point_Wet"]; //требуемая влажность
var wetTime = Number(ps["wetTime"]); //время (длительность) полива
var sunraiseStartTime; //Время начала "рассвета"
var sunraiseStopTime; //Время конца "рассвета"
var sunsetStartTime;//Время начала "заката"
var sunsetStopTime; //Длительность "заката"
var light_increment = 0; //Глобальная для хранения приращения освещенности
var setPointLight = (((ps["light_setpoint"])-1)*100).toString(); // уставка освещенности
//var dimmer_increment = (dimmer_maxValue-dimmer_zeroValue)/400; //увеличение освещения в цикл расчетное на 0.25%
var dimmer_increment = 100; //увеличение освещения в цикл 1%
setTimeVariable();

//Проверим на null переменную из хранилища 
//и дадим какое-то значение, на случай "нового" скрипта.

if (!ps["sun_stop_time"]){
  log.info("sun_stop_time undefined")
  ps["sun_stop_time"]="18:00"
}


//Элементы виртуального устройства
//управления
var deviceCells = { 
  "Lamp power set" : {
    type : "range",
    value : dimmer_zeroValue,
    min : dimmer_zeroValue,
    max : dimmer_maxValue
  },
  //Начало рассвета hh:mm
  "Sunraise (start) time": {
    type: "text",
    readonly: false,
    value: ps["sun_start_time"],
  },
  //Длительность рассвета
  "Sunraise duration": {
    type: "text",
    readonly: false,
    value: ps["sun_start_duration"],
  },
  //Начало заката hh:mm
  "Sunset (stop) time": {
    type: "text",
    readonly: false,
    value: ps["sun_stop_time"],
  },
  //Длительность заката
  "Sunset duration": {
    type: "text",
    readonly: false,
    value: ps["sun_stop_duration"],
  },
  "Light SetPoint": {
    type: "value",
    readonly: false,
    value: ps["light_setpoint"]
  },

  //Влажность включения
  "Set Point Wet": {
    type: "value",
    readonly: false,
    value: ps["set_Point_Wet"],
  },
  //Время полива
  "Wet Time": {
    type: "text",
    readonly: false,
    value: ps["wetTime"],
  },
  pumpwork : {
          type : "switch",
          value : false,
  }, 
  sunraiseProcess : {
          type : "switch",
          value : false,
  },   
  sunsetProcess : {
          type : "switch",
          value : false,
  },
  dayProcess : {
          type : "switch",
          value : false,
  },
};



//Создадим виртуальное устройство и добавим в него элементы 
  defineVirtualDevice("light_"+grow_box, {
    title:"Light of "+grow_box,
    cells: deviceCells
  });

defineRule("Set Point Wet change", { //название правила 
whenChanged: "light_"+grow_box+"/Set Point Wet", //при изменении поля желаемой влажности запишем его в хранилище
  then: function (newValue, devName, cellName) { //выполняй следующие действия
    log.info("light_"+grow_box+"/Set Point Wet", newValue); //Это лог. Он попадает в /var/log/messages
    ps["set_Point_Wet"] = newValue;
    setpointwet = newValue;
  }
});

defineRule("Wet Time change", { //название правила 
whenChanged: "light_"+grow_box+"/Wet Time", //при изменении поля желаемого времени полива запишем его в хранилище
  then: function (newValue, devName, cellName) { //выполняй следующие действия
    log.info("light_"+grow_box+"/Wet Time", newValue); //Это лог. Он попадает в /var/log/messages
    ps["wetTime"] = newValue;
    wetTime = Number(newValue);
    setTimeVariable();
  }
});

defineRule("Sunraise start time change", { //название правила 
whenChanged: "light_"+grow_box+"/Sunraise (start) time", //при изменении поля времени начала рассвета запишем его в хранилище
  then: function (newValue, devName, cellName) { //выполняй следующие действия
    log.info("light_"+grow_box+"/Sunraise start time ", newValue); //Это лог. Он попадает в /var/log/messages
    ps["sun_start_time"] = newValue;
    setTimeVariable();
  }
});

defineRule("Sunraise duration change", { //название правила 
whenChanged: "light_"+grow_box+"/Sunraise duration", //при изменении поля времени рассвета запишем его в хранилище
  then: function (newValue, devName, cellName) { //выполняй следующие действия
    log.info("light_"+grow_box+"/Sunraise duration", newValue); //Это лог. Он попадает в /var/log/messages
    ps["sun_start_duration"] = newValue;
    setTimeVariable();
  }
});

defineRule("Sunset start time change", { //название правила 
whenChanged: "light_"+grow_box+"/Sunset (stop) time", //при изменении поля времени начала ЗАКАТА запишем его в хранилище
  then: function (newValue, devName, cellName) { //выполняй следующие действия
    log.info("light_"+grow_box+"/Sunset (stop) time ", newValue); //Это лог. Он попадает в /var/log/messages
    ps["sun_stop_time"] = newValue;
    setTimeVariable();
  }
});

defineRule("Sunset duration change", { //название правила 
whenChanged: "light_"+grow_box+"/Sunset duration", //при изменении поля времени заката запишем его в хранилище
  then: function (newValue, devName, cellName) { //выполняй следующие действия
    log.info("light_"+grow_box+"/Sunset duration", newValue); //Это лог. Он попадает в /var/log/messages
    ps["sun_stop_duration"] = newValue;
    setTimeVariable();
  }
});

defineRule("Light SetPoint change", { //название правила 
whenChanged: "light_"+grow_box+"/Light SetPoint", //при уставки желаемой освещенности -запишем в хранилище
  then: function (newValue, devName, cellName) { //выполняй следующие действия
    log.info("light_"+grow_box+"/light_setpoint ", newValue); //Это лог. Он попадает в /var/log/messages
    ps["light_setpoint"] = ((newValue-1)*100).toString();
    setPointLight = ((newValue-1)*100).toString();
  }
});
defineRule("dayProcess change", { //название правила 
whenChanged: "light_"+grow_box+"/dayProcess", // Для режима "День"
  then: function (newValue, devName, cellName) { //выполняй следующие действия
    if (newValue){ //Включаем "день"
    //log.info("light_"+grow_box+"/light_setpoint ", newValue); //Это лог. Он попадает в /var/log/messages
      dev["light_"+grow_box+"/sunraiseProcess"] = false; //Выключаем "рассвет" Таймер остановит правило "SunRaise_starter"
      //dev["light_"+grow_box+"/sunsetProcess"] = false; //Выключаем "закат" Таймер остановит правило "SunSet_starter"
      setPointLight = Number(ps["light_setpoint"]); // уставка освещенности
    }else{
      //dev[dimmer_light] = dimmer_zeroValue;
    }
  }
});

//* Статический сценарий

defineRule("start change", { //название правила 
whenChanged: "light_"+grow_box+"/sunraiseProcess", //При изменении флага "рассвет" - установим значения виртуального устройства.
  then: function (newValue, devName, cellName) { //выполняй следующие действия
    if ((dev["light_"+grow_box]["sunraiseProcess"]==true)){// если сейчас нужен свет
      newValue = Number(newValue); //Приведем к числу
      if (newValue>setPointLight) { // Если текущая освещенность 0
        //log.info("light_"+grow_box+"Light_measured BIG",newValue);
        if (dev[dimmer_light]<dimmer_maxValue){
          dev[dimmer_light] += dimmer_increment;
        }
      }
      dev["light_"+grow_box+"/Lamp power set"] = dev[dimmer_light];
    }
  }
});

defineRule("start_sunraise change", { //название правила 
whenChanged: "light_"+grow_box+"/sunraiseProcess", //При изменении флага "рассвет" - установим значения виртуального устройства.
  then: function (newValue, devName, cellName) { //выполняй следующие действия
    dev["light_"+grow_box]["dimmer_light"] = newValue;
    if ((dev["light_"+grow_box]["sunraiseProcess"]==true)){// если сейчас нужен свет
      newValue = Number(newValue); //Приведем к числу
        if (dev[dimmer_light]=0){
          dev[dimmer_light] += dimmer_increment;
      }
      dev["light_"+grow_box+"/Lamp power set"] = dev[dimmer_light];
    }
  }
});
defineRule("start_sunset change", { //название правила 
whenChanged: "light_"+grow_box+"/sunsetProcess", //При изменении флага "закат" - установим значения виртуального устройства.
  then: function (newValue, devName, cellName) { //выполняй следующие действия
    dev["light_"+grow_box]["dimmer_light"] = newValue;
    if ((dev["light_"+grow_box]["sunraiseProcess"]==true)||(dev["light_"+grow_box]["dayProcess"]==true)||(dev["light_"+grow_box]["sunsetProcess"]==true)){// если сейчас нужен свет
      newValue = Number(newValue); //Приведем к числу
      if (newValue>setPointLight) { // Если текущая освещенность больше уставки
        //log.info("light_"+grow_box+"Light_measured BIG",newValue);
        if (dev[dimmer_light]>dimmer_zeroValue){
          dev[dimmer_light] -= dimmer_increment;
        }
      } else{ // если меньше
        //log.info("light_"+grow_box+"Light_measured LOW",newValue);
        if (dev[dimmer_light]<dimmer_maxValue){
          dev[dimmer_light] += dimmer_increment;
        }
      }
      dev["light_"+grow_box+"/Lamp power set"] = dev[dimmer_light];
    }
  }
});
defineRule("start_day change", { //название правила 
whenChanged: dimmer_light, //При изменении флага "день" - установим значения виртуального устройства.
  then: function (newValue, devName, cellName) { //выполняй следующие действия
    dev["light_"+grow_box]["dimmer_light"] = newValue;
    if ((dev["light_"+grow_box]["sunraiseProcess"]==true)||(dev["light_"+grow_box]["dayProcess"]==true)||(dev["light_"+grow_box]["sunsetProcess"]==true)){// если сейчас нужен свет
      newValue = Number(newValue); //Приведем к числу
      if (newValue>setPointLight) { // Если текущая освещенность больше уставки
        //log.info("light_"+grow_box+"Light_measured BIG",newValue);
        if (dev[dimmer_light]>dimmer_zeroValue){
          dev[dimmer_light] -= dimmer_increment;
        }
      } else{ // если меньше
        //log.info("light_"+grow_box+"Light_measured LOW",newValue);
        if (dev[dimmer_light]<dimmer_maxValue){
          dev[dimmer_light] += dimmer_increment;
        }
      }
      dev["light_"+grow_box+"/Lamp power set"] = dev[dimmer_light];
    }
  }
});
defineRule("dayProcess change on", { //название правила 
whenChanged: "light_"+grow_box+"/sunraiseProcess", // Для режима "День"
  then: function (newValue, devName, cellName) { //выполняй следующие действия
    if ((dev["light_"+grow_box]["sunraiseProcess"]==false)){ //если рассвет выключается
      dev["light_"+grow_box+"/dayProcess"] = true; // то "день" включается
    }
  }
});

//* Окончание статического сценария
//* дополнение для полива

var timerWetId = null;
defineRule("WET change", { //название правила 
whenChanged: sensor_wet, //При изменении измеренной влажности - определим необходимость полива.
  then: function (newValue, devName, cellName) { //выполняй следующие действия
    newValue = Number(newValue); //Приведем к числу
    log.info("Timer start_0", wetTime)
    dev["light_"+grow_box]["sensor_wet"] = newValue;
    if ((dev["light_"+grow_box]["dayProcess"])&&(newValue<setpointwet)){//День и увлажнение требуется
      if (!timerWetId){ //Если таймер еще не запущен
        dev["light_"+grow_box+"/pumpwork"] = true; //Включаем насос
        timerWetId = setTimeout(function () { //Начнем описывать таймер
            dev["light_"+grow_box+"/pumpwork"] = false; //ВЫключаем насос   (тут можно описать требуемое действие)
            timerWetId = null; //Сбрасываем идентификатор отработавшего таймера
          }, wetTime);
      }
    }
  }
});

defineRule("WetProcess change", { //название правила 
whenChanged: "light_"+grow_box+"/pumpwork", // Отслеживаем состояние контрола, вся логика - в правиле выше
  then: function (newValue, devName, cellName) { //выполняй следующие действия
      dev[pump_wet] = newValue; // Помпа включается вместе с контролом.
  }
});

//* Окончание дополнения для полива

defineRule("cron minute timer", { //Просто задание, которое выполняется каждую минуту и взводит/опускает флаги "Рассвет", "Закат"
  when: cron("00 * * * * *"),
  then: function () {
    //log.info(grow_box, "cron timer executed! DEBUG ONLY.");
    d = new Date(); //Текущее время
    //sunraiseStartTime 
    if ((dev["light_"+grow_box]["sunraiseProcess"]==false) && (d > sunraiseStartTime) && (d<sunraiseStopTime)){
      log.info(grow_box, "cron timer executed! Sunraise process START", "sunraiseStartTime",sunraiseStartTime ,"sunraiseStopTime",sunraiseStopTime);
      dev["light_"+grow_box]["sunraiseProcess"] = true;
    }
    //sunsetStartTime
    if ((dev["light_"+grow_box]["sunsetProcess"]==false) && (d > sunsetStartTime) && (d<sunsetStopTime)){
      log.info(grow_box, "cron timer executed! SunSET process START", "sunsetStartTime",sunsetStartTime ,"sunsetStopTime",sunsetStopTime);
      dev["light_"+grow_box]["sunsetProcess"] = true;
    }
    //dayProcess
    if ((dev["light_"+grow_box]["dayProcess"]==false) && (d > sunraiseStopTime) && (d<sunsetStartTime)){
      log.info(grow_box, "cron timer executed! DAY process START","sunraiseStopTime",sunraiseStopTime,"sunsetStartTime",sunsetStartTime);
      dev["light_"+grow_box]["dayProcess"] = true;
    }
  }
});

defineRule("cron day timer", { //Просто задание, которое выполняется раз в сутки и меняет дату в переменных на текущую.
  when: cron("01 00 00 * * *"),
  then: function () {
    setTimeVariable();
  }
});

function string_to_time(srcString) { 
  //log.info("string_to_time_"+grow_box, srcString)
  var d = new Date();
  var datetime = new Date(d.getFullYear()+'-'+(d.getMonth()+1)+'-'+d.getDate()+'T' + srcString + 'Z');
  datetime.setMinutes(datetime.getMinutes() + datetime.getTimezoneOffset());//Приведем к локальному:
  return datetime; 
};


function setTimeVariable() { 
  sunraiseStartTime = string_to_time(ps["sun_start_time"]); //Время начала "рассвета"
  sunraiseStopTime = new Date(sunraiseStartTime);
  sunraiseStopTime.setMinutes(sunraiseStopTime.getMinutes() + parseInt(ps["sun_start_duration"])); //окончание "рассвета"
  sunsetStartTime = string_to_time(ps["sun_stop_time"]);//Время начала "заката"
  sunsetStopTime = new Date(sunsetStartTime);
  sunsetStopTime.setMinutes(sunsetStopTime.getMinutes() + parseInt(ps["sun_stop_duration"])); //окончание "заката"
};


defineRule("SunRaise_starter", { //название правила 
whenChanged: "light_"+grow_box+"/sunraiseProcess", //При изменении переуключателя "рассвет"
  then: function (newValue, devName, cellName) { //выполняй следующие действия
    log.info("light_"+grow_box+" sunraiseProcess function", newValue, devName, cellName); //Это лог.
    if (newValue){ //Запускаем "рассвет"
      dura = (sunraiseStopTime - sunraiseStartTime)/1000; //время в секундах
      setPointLight = Number(ps["light_setpoint"]); // уставка освещенности
      light_increment = setPointLight/dura; //увеличение освещенности в секунду расчетное
      setPointLight = 1;
	  log.info("light_"+grow_box+" sunraiseProcess", "dura", dura, "dimmer_increment", dimmer_increment); //Это лог.
      startTicker(grow_box+"raiseTicker", 1000); //Запуск таймера, отрабатывает раз в секунду.
    } else { //Останавливаем "рассвет"
      timers[grow_box+"raiseTicker"].stop(); 
      log.info("light_"+grow_box+"Ticker STOP sunraise");
    }
  }
});

defineRule("SunSet_starter", { //название правила 
whenChanged: "light_"+grow_box+"/sunsetProcess", //При изменении переуключателя "Закат"
  then: function (newValue, devName, cellName) { //выполняй следующие действия
    log.info("light_"+grow_box+" sunsetProcess function", newValue, devName, cellName); //Это лог.
    if (newValue){ //Запускаем "закат"
      dev["light_"+grow_box]["dayProcess"] = false;
      setPointLight = Number(ps["light_setpoint"]); // уставка освещенности
      dura = (sunsetStopTime - sunsetStartTime)/1000; //время в секундах
      light_increment = -(setPointLight)/dura; //уменьшение освещения в секунду расчетное. От уставки!
      //dev["light_"+grow_box+"/dayProcess"] = false; //Выключаем "день"
	  log.info("light_"+grow_box+" sunsetProcess", "dura", dura, "light_increment", light_increment, "setPointLight", setPointLight); //Это лог.
      startTicker(grow_box+"raiseTicker", 1000); //Запуск таймера, отрабатывает раз в секунду.
    } else { //Останавливаем "закат"
      timers[grow_box+"raiseTicker"].stop(); 
      log.info("light_"+grow_box+"Ticker STOP sunset");
      setPointLight = 0;
      dev[dimmer_light] = dimmer_zeroValue;
    }
  }
});


defineRule("handmadeSunTicker", { // Таймер плавного рассвета/заката
  when: function () { return timers[grow_box+"raiseTicker"].firing; },
  then: function () {
    setPointLight += light_increment;
    if (setPointLight>Number(ps["light_setpoint"])){
      log.info("light_"+grow_box+"raiseTicker STOP ON setPointLight");
      dev["light_"+grow_box+"/sunraiseProcess"] = false; //Выключаем "рассвет" Таймер остановит правило "SunRaise_starter"
    }
    if (setPointLight<0){
      log.info("light_"+grow_box+"setTicker STOP ON setPointLight");
      dev["light_"+grow_box+"/sunsetProcess"] = false; //Выключаем "закат" Таймер остановит правило "SunSet_starter"
    }
    if ((dev["light_"+grow_box+"/Lamp power set"]>dimmer_maxValue)||(dev["light_"+grow_box+"/Lamp power set"]<dimmer_zeroValue)){
      log.info("light_"+grow_box+"raiseTicker STOP ON Lamp power set");
      dev["light_"+grow_box+"/sunraiseProcess"] = false; //Выключаем "рассвет" Таймер остановит правило "SunRaise_starter"
      dev["light_"+grow_box+"/sunsetProcess"] = false; //Выключаем "закат" Таймер остановит правило "SunSet_starter"
    }
  }
});

Дописать, конечно можно.

Бывает) я бы её сам точно не нашёл. Спасибо) завтра проверю. Добавьте пожалуйста задержку после того, как отключится реле. Если не сложно. Дальше процессы в теплице почти однотипные, с точки зрения автоматизации и там я уже сам справлюсь. Спасибо вам огромное за работу и поддержку. Я останусь в этой теме. Если что, я обращусь. Со следующей недели, ради любопытства, попробую настроить scada систему для какого-то графического оформения. Там есть много подробных видео, я разберусь. Спасибо огромное!

Всегда пожалуйста, наши пользователь - самое ценное что у нас есть. :wink:
Вообще скрипт уже вырос, надо переделать сохранение в оду функцию будет, а то уже неудобно мотать.
Насчет scada - попробуйте MasterScada.

Доброе утро. Да, он работает. Спасибо Вам огромное. Мне немного неловко просить, но можно попросить Вас добавить туда задержку по времени после выключения помпы? и как бы перевести мс в минуты? спасибо

Фиксированную или настраиваемую?

Не секунды, именно минуты?

Настраиваемую

да, минуты.

Мне тут ещё кучу вводных навалили. Но я как-нибудь с эними сам разберусь. Спасибо

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

Вот тут и поможет унификация, потому что сейчас количество кода - велико, надо в йункцию упаковывать.

Здравствуйте. Провели эксперимент: подключили 13 драйверов XLG-240-L-AB к 1 выходу WB-MAO4
Общая мощность установки: 3120 Вт
Поток облучённости при подключении 2х драйверов на выход: 152.5 мкмоль/с/м2
Поток облучённости при подключении 13и драйверов на выход: 165.3 мкмоль/с/м2
Диммируется от 0% до 100% хорошо.
Будет возможность, попробуем большее количество драйверов

1 лайк

Вся боль в управлении теплицой при использовании вайренборда в качестве ПЛК - выше))
изинините:)

Поделитесь?
Правда, интересно.

Честно, вайренборд больше чем устраивает. Возможностей на самом деле очень много и ими покрывается весь необходимый спектр задач. Самое большое ограничение, на данный момент- это количество знаний и опыт работы

1 лайк

Здравствуйте. В ближайшее время вводим в эксплуатацию большой комплекс стеллажных систем под управлением WB. По возможности сделаю видео обзор на то, как это получилось. Плюс строится большая теплица, в которой управление освещением будет тоже под управлением WB и по написанным Вами правилам (за что Вам огромное спасибо). Тут в разработке появился личный проект закрытой экосистемы с облаками, дождём, солнцем и тд… Если в 2х словах, то это аквариум с растениями типа “бонсай”. Такой вот вопрос: у нас с Вами в правиле цикл должен укладываться в 24 часа и укладываться в астрономический день. Можно ли сделать годовой цикл со сменой температуры, светового дня (как в нашем текущем случае) и тд? Если да, то было бы интересно над этим поработать, если нет, то ничего страшного. Такая же необходимость есть и при выращивании растений. Условный цикл разделяется на 3 части с разной интенсивностью света и было бы хорошо сделать автоматизацию этого периода, чтобы прокручивать 3 части цикла (каждая часть по 10 дней, условно), а потом зациклить, чтобы эти циклы повторялись постоянно

1 лайк