Автономный автополив на 1-12 комнатных растений на Arduino

Тема в разделе "Глядите, что я сделал", создана пользователем EandV, 8 окт 2018.

?

Как вам проект?

  1. Хорошая идея и реализация

  2. Сделано неплохо, но нужно дорабатывать

  3. Так себе

  4. Тема хорошая, но я бы сделал по другому

  5. Системы автополива не особо интересны

  6. По теме полно готовых проектов, нет смысла придумывать что-то своё

  7. Размещать здесь не стоило, не особо интересно

  8. Вызывает негатив

Результаты будут видны только после голосования.
  1. EandV

    EandV Нерд

    Всем привет!

    Я относительно недавно увлекся самоделками и теперь хочу выставить свои скромные проекты на суд общественности. Начну с системы автополива для комнатных растений.

    Выглядит это примерно вот так:

    Блок управления
    4.jpg
    Емкость с помпами и трубками
    IMG_20180730_215543.jpg

    2.jpg IMG_20180825_045615.jpg IMG_20180825_181906.jpg
    IMG_20180825_182046.jpg




    Если интерес остался, то дальше, собственно говоря, опишу свой проект.

    Требования к системе были следующие:
    1. Автономная работа минимум 1 месяц
    2. Должна быть возможность настраивать количество поливаемых растений
    3. Время срабатывания помп должно настраиваться с точностью до часа
    4. Должно быть информирование:
      • Текущие настройки для каждой помпы
      • Сколько дней осталось до срабатывания каждой помпы
      • Уровень заряда аккумулятора
      • Индикация, что идет зарядка аккумулятора от солнечной батареи
    Мой проект

    Система состоит из 3х помп. Настройки работы каждой помпы задаются отдельно. Маленькие помпы можно использовать с гребенками - разветвителями на 3-4 крана. В итоге можно поливать до 12 растений. Помимо программных настроек работы помп, дополнительные настройки делаются кранами.

    На дисплей выводится следующая «таблица»: строки – номера помп, столбцы информация по каждой помпе.
    • ПР – период работы. Раз в сколько дней будет срабатывать помпа.
    • ЧР- час работы. Указывается час (например «19» - помпа сработает в 19:00), кода сработает помпа.
    • ВР – время работы помпы. Указывается в секундах на сколько включится помпа.
    • ДО – дней осталось. Через сколько дней произойдет ближайший полив.
    • Также выводится текущие время и дата
    Можно программно отключить 2 и/или 3 помпу, тогда выводится информация только по активным помпам.

    Меры по обеспечению автономности:
    • 3 аккумулятора 18650
    • Питание от солнечной батареи
    • Ардуино уходит в Powerdown и просыпается по Watсhdog
    • У Ардуино выпаял стабилизатор напряжения
    • Дисплей Nokia
    • Дисплей находится в выключенном состоянии, включается только после удержания кнопки, после этого через некоторое время опять выключается
    • Все индикаторы либо выпаяны с модулей, либо вынесены на панель и включаются только при удержании кнопок.
    Детали:
    • Корпус из коробки для еды за 40р из Ашана
    • Arduino nano
    • Дисплей Nokia
    • Модуль часов DS3231
    • Аккумуляторы 18650 в холдере
    • Повышающий модуль до 5В
    • Понижающий модуль до 3,3В для дисплея
    • Модуль зарядки аккумулятора TP4056
    • Индикатор зарядки аккумулятора
    • Солнечная батарея
    • Электролитические и керамические конденсаторы, резисторы, светодиоды, полевые транзисторы
    • Кнопки и выключатели

    Схема
    Plant_water_bb3.jpg

    Общий алгоритм работы программы:
    • Просыпаемся по Вотчдогу
    • Снимаем текущие данные по времени и дате
    • Если дата изменилась, считаем количество прошедших дней для каждой помпы
    • Если число прошедших дней совпадает с периодом работы в настройках - проверяем час.
    • Если час с модуля времени равен часу указанному в настройках для помпы, подаем напряжение на Пин помпы далее задержка кода (равная интервалу полива из настроек), отключаем напряжение на Пине, сбрасываем счетчик прошедших дней для данной помпы.
    • В каждом цикле уходим в сон
    • При удержании кнопки активизируется дисплей и отображает информацию. При смене минуты в модуле времени дисплей отключается.

    Хотел бы услышать ваши рекомендации по доработке.


     
  2. parovoZZ

    parovoZZ Гуру

    не умеет работать с солнечными панелями, т.к. не отслеживает точку максимальной мощности.
    на данный момент моветон. Есть мк со встроенным RTC.
     
  3. EandV

    EandV Нерд

    Конкретно моя панель выдает 4-5 В и мне с помощью этого модуля удалось зарядить полностью 1 банку 18650. Т.е. кое-как но заряжает. Согласен, что решение не самое хорошее, но для обеспечения автономности системы хватает.

    По поводу решения с DS3231. Ну да, есть куда расти. Поэтому тут и выложил, чтобы узнать мнение опытных людей.
     
    Последнее редактирование: 8 окт 2018
  4. DIYMan

    DIYMan Гуру

    Не парься - DS3231 - вполне годное решение. Там есть нога SQW, её можно настраивать, чтобы периодически дрыгала ногой, например, для целей периодического пробуждения МК. Как по мне - очень удобная фича для использования во многих проектах, где - нет RTC в МК. Да и по стоимости - копейки, плюс, если брать готовые модули от китайцев - там ещё и EEPROM халявная стоит, можно юзать для хранения своих данных.
     
    DetSimen нравится это.
  5. DetSimen

    DetSimen Гуру

  6. EandV

    EandV Нерд

    Интересная инфа, спасибо!
     
  7. Vovka

    Vovka Гик

    А где датчики влажности? Или тупо льет по времени?
     
  8. EandV

    EandV Нерд

    Тупо льет по времени. Просто подобрал подходящие интервалы.
     
  9. DIYMan

    DIYMan Гуру

    lepidot нравится это.
  10. EandV

    EandV Нерд

    Спасибо за инфо. Такой датчик уже заказал, чтобы его потестить. Но особого смысла в них не вижу в моем случае. Дождь у меня в квартире не идет, поэтому поливать мокрую почву система не будет. А потратить по 1 минуте чтобы перепрошить систему 4 раза в год (Лето - полив раз в 4 дня, весна-осень - раз в 5 дней, зима - раз в 10 дней) мне не особо сложно. Специально не стал усложнять систему датчиками.
     
  11. DetSimen

    DetSimen Гуру

    дак это ж можно и программно отслеживать по RTC, не? Чо перепрошивать то? Ячейки памяти, чай, не резиновые
     
    EandV и parovoZZ нравится это.
  12. EandV

    EandV Нерд

    Оно так и работает собственно. В коде есть переменные с настройками (прописываются в теле кода в разделе:"// Настройки полива"). Код обращется к модулю и снимает с него данные. Когда получает нужные данные, врубает полив.

    Прикладываю код. Понимаю, что быдлокодинг. Не судите строго Нуба )

    Код (C++):

    #include <Wire.h>                           // Подключаем библиотеку Wire                          
    #include <TimeLib.h>                        // Подключаем библиотеку TimeLib
    #include <DS1307RTC.h>                      // Подключаем библиотеку DS1307RTC
    #include <Adafruit_GFX_rus.h>               // Подключаем библиотеку Экран Нокиа
    #include <Adafruit_PCD8544_rus.h>           // Подключаем библиотеку Экран Нокиа
    #include <avr/wdt.h>                        // Подключаем библиотеку сторожевого таймера
    #include <avr/sleep.h>                      // Подключаем библиотеку энергосбережения
    Adafruit_PCD8544 display = Adafruit_PCD8544(3, 4, 5, 6, 7); // Обозначаем пины для экрана
    // Обозначаем переменные

    boolean flag;
    int startminute ;
    int nowminute;

    int periodwork;
    int hourwork;
    int contwork;
    int dayscount;
    int startday;
    int nowday;
    int delaytime;
    int polivflag;
    int nowhour;


    boolean  pomp2activate;
    int periodwork2;
    int hourwork2;
    int contwork2;
    int dayscount2;
    int startday2;
    int nowday2;
    int delaytime2;
    int polivflag2;
    int nowhour2;

    boolean  pomp3activate;
    int periodwork3;
    int hourwork3;
    int contwork3;
    int dayscount3;
    int startday3;
    int nowday3;
    int delaytime3;
    int polivflag3;
    int nowhour3;

    void setup() {
     
    // Настройки полива

    periodwork = 5; // Раз в сколько дней производится полив
    hourwork = 19;   // час когда производится полив
    contwork = 30;  // время полива в секундах

    pomp2activate = 1;
    periodwork2 = 5; // Раз в сколько дней производится полив
    hourwork2 = 20;   // час когда производится полив
    contwork2 = 25;  // время полива в секундах

    pomp3activate = 1;
    periodwork3 = 5; // Раз в сколько дней производится полив
    hourwork3 = 21;   // час когда производится полив
    contwork3 = 30;  // время полива в секундах

    pinMode(A2,INPUT_PULLUP);

    // Настраиваем дисплей
    //display.begin();
    //display.clearDisplay();
    //display.display();
    //display.setContrast(60); // установка контраста
    //delay(1000);
    //display.setTextSize(1);  // установка размера шрифта
    //display.setTextColor(BLACK); // установка цвета текста
    //display.setCursor(0,0); // установка позиции курсора

    dayscount = 0;
    nowday =0;
    delaytime = contwork*1000;
    pinMode(9,OUTPUT);
    polivflag=0;


    tmElements_t tm;
    if (RTC.read(tm)) {
     
    startday = (tm.Day);
    if (pomp2activate == 1){
    startday2 = (tm.Day);
    }
    if (pomp3activate == 1){
    startday3 = (tm.Day);
    }

    } // if (RTC.read(tm))

    if (pomp2activate == 1){
    dayscount2 = 0;
    nowday2 =0;
    delaytime2 = contwork2*1000;
    pinMode(10,OUTPUT);
    polivflag2=0;
    }

    if (pomp3activate == 1){
    dayscount3 = 0;
    nowday3 =0;
    delaytime3 = contwork3*1000;
    pinMode(11,OUTPUT);
    polivflag3=0;
    }

    } // void setup()

    void loop(){
    //Включаем энергосбережение
    wdt_enable(WDTO_8S); //Задаем интервал сторожевого таймера (8с)
    WDTCSR |= (1 << WDIE); //Устанавливаем бит WDIE регистра WDTCSR для разрешения прерываний от сторожевого таймера
    set_sleep_mode(SLEEP_MODE_PWR_DOWN); //Устанавливаем интересующий нас режим
    sleep_mode(); // Переводим МК в спящий режим

     
    delay(50);
    tmElements_t tm;
    if (RTC.read(tm)) {
    nowminute  = (tm.Minute);
    boolean button1 = !digitalRead(A2); // инвертируем сигнал
    //Serial.println(button1);

    // Вывод на экран

    if (button1==1) {
    flag = 1;
    startminute = nowminute;

    display.begin();
    display.clearDisplay();
    display.display();
    display.setContrast(60); // установка контраста
    delay(1000);
    display.setTextSize(1);  // установка размера шрифта
    display.setTextColor(BLACK); // установка цвета текста
    display.setCursor(0,0); // установка позиции курсора

    display.clearDisplay();
    display.display();

    display.print("   ПР ЧР ВР ДО");
    display.print("П1 ");
    if (periodwork < 10)  {
       display.print(" ");
       display.print (periodwork);
    } else {
    display.print (periodwork);
    }
    display.print(" ");
    if (hourwork < 10)  {
    display.print(" ");
    display.print (hourwork);
    } else {
    display.print (hourwork);
    }
    display.print(" ");
    if (contwork < 10)  {
    display.print(" ");
    display.print (contwork);
    } else {
    display.print (contwork);
    }
    if (contwork < 100)  {
       display.print(" ");
    }
    if (periodwork - dayscount < 10)  {
    display.print(" ");
    display.print (periodwork - dayscount);
    } else {
    display.print (periodwork - dayscount);
    }
    } // if (button1==1)



    nowday  = (tm.Day);

    if (nowday != 0 && nowday != startday ) {
    dayscount=dayscount+1;
    polivflag=0;
    startday = nowday;
    }
    if(dayscount == periodwork){
    nowhour = (tm.Hour);

    if (nowhour == hourwork && polivflag==0) {
      digitalWrite(9,HIGH);
      delay (2000);
      digitalWrite(9,LOW);
      delay (5000);
      digitalWrite(9,HIGH);
      delay(delaytime);
      digitalWrite(9,LOW);
      polivflag=1;
      dayscount=0;
    } // if (nowhour == hourwork && polivflag==0)

    } // if(dayscount == periodwork)

    // Такой же блок, для 2 помпы

    if (pomp2activate == 1){



      if (button1==1) {
    display.print("П2 ");
    if (periodwork2 < 10)  {
       display.print(" ");
       display.print (periodwork2);
    } else {
    display.print (periodwork2);
    }
    display.print(" ");
    if (hourwork2 < 10)  {
    display.print(" ");
    display.print (hourwork2);
    } else {
    display.print (hourwork2);
    }
    display.print(" ");
    if (contwork2 < 10)  {
    display.print(" ");
    display.print (contwork2);
    } else {
    display.print (contwork2);
    }
    if (contwork2 < 100)  {
       display.print(" ");
    }
    if (periodwork2 - dayscount2 < 10)  {
    display.print(" ");
    display.print (periodwork2 - dayscount2);
    } else {
    display.print (periodwork2 - dayscount2);
    }
    }//if (button1==1) {

    nowday2  = (tm.Day);

    if (nowday2 != 0 && nowday2 != startday2 ) {
    dayscount2=dayscount2+1;
    polivflag2=0;
    startday2 = nowday2;
    }
    if(dayscount2 == periodwork2){
    nowhour2 = (tm.Hour);

    if (nowhour2 == hourwork2 && polivflag2==0) {
      digitalWrite(10,HIGH);
      delay (2000);
      digitalWrite(10,LOW);
      delay (5000);
      digitalWrite(10,HIGH);
      delay(delaytime2);
      digitalWrite(10,LOW);
      polivflag2=1;
      dayscount2=0;
    } // if (nowhour2 == hourwork2 && polivflag2==0)

    } // if(dayscount2 == periodwork2)

     

     
    } // if (pomp2activate == 1)

    // Такой же блок, для 3 помпы

    if (pomp3activate == 1){
      if (button1==1) {
    display.print("П3 ");
    if (periodwork3 < 10)  {
       display.print(" ");
       display.print (periodwork3);
    } else {
    display.print (periodwork3);
    }
    display.print(" ");
    if (hourwork3 < 10)  {
    display.print(" ");
    display.print (hourwork3);
    } else {
    display.print (hourwork3);
    }
    display.print(" ");
    if (contwork2 < 10)  {
    display.print(" ");
    display.print (contwork3);
    } else {
    display.print (contwork3);
    }
    if (contwork3 < 100)  {
       display.print(" ");
    }
    if (periodwork3 - dayscount3 < 10)  {
    display.print(" ");
    display.print (periodwork3 - dayscount3);
    } else {
    display.print (periodwork3 - dayscount3);
    }
    } //if (button1==1) {
    nowday3  = (tm.Day);

    if (nowday3 != 0 && nowday3 != startday3 ) {
    dayscount3=dayscount3+1;
    polivflag3=0;
    startday3 = nowday3;
    }
    if(dayscount3 == periodwork3){
    nowhour3 = (tm.Hour);

    if (nowhour3 == hourwork3 && polivflag3==0) {
      digitalWrite(11,HIGH);
      delay (2000);
      digitalWrite(11,LOW);
      delay (5000);
      digitalWrite(11,HIGH);
      delay(delaytime3);
      digitalWrite(11,LOW);
      polivflag3=1;
      dayscount3=0;
    } // if (nowhour3 == hourwork3 && polivflag3==0)

    } // if(dayscount3 == periodwork3)
     
    } // if (pomp3activate == 1){



    //Вывод текущих даты и времени
    //display.println(" ");
    if (button1==1) {
    display.print(tm.Hour);
    display.print(':');
    if (tm.Minute < 10)  {
    display.print("0");
    display.println (tm.Minute);
    } else {
    display.println (tm.Minute);
    }
    display.print(tm.Day);
    display.print('/');
    display.print(tm.Month);
    display.print('/');
    display.print(tmYearToCalendar(tm.Year));
    display.print(" ");
    display.display();
    }//if (button1==1) {

    if (startminute != nowminute) {
       flag = 0;
    }

    if (flag == 0) {
    digitalWrite(3, LOW);
    digitalWrite(4, LOW);
    digitalWrite(5, LOW);
    digitalWrite(6, LOW);
    digitalWrite(7, LOW);
    }

    } // if (RTC.read(tm))

    } // void loop()

    ISR (WDT_vect) {
      wdt_disable();
    }
     
  13. EandV

    EandV Нерд

    Хотя наверно другое имелось в виду. Прописать в коде, что если месяц апрель, то поливать не раз в 10 дней, а раз в 5 дней. Правильно понял?
     
  14. DetSimen

    DetSimen Гуру

    да. и так по всем месяцам
     
  15. Vovka

    Vovka Гик

    Только учтите, год году рознь: то весна раньше придет, то зима... Я бы все же привязывался к датчикам влажности. Кстати, вот еще варианты датчиков
     
  16. EandV

    EandV Нерд

    Хорошая идея. Пожалуй так и сделаю. Спасибо!
     
  17. EandV

    EandV Нерд

    Спасибо хорошая подборка. На многих форумах обращал внимание, что датчики влажности почвы в системах полива - это некая сакральная тема, которая разделяет самодельщиков на 2 лагеря. Я лично себя не к одному из них не отношу. Ничего против датчиков не имею.

    Только по-моему целесообразно их применять в следующих случаях:
    1. Открытый грунт. Если прошел дождь, поливать больше не нужно, это разумно
    2. Всё серьезно. У Вас целая оранжерея, где всё измеряется, управляется и регулируется: полив, влажность воздуха, освещение, вентиляция и т.д. Наверно это имеет смысл при выращивании каких-то экзотических растений, либо получения максимальной урожайности чего-либо. Всё это не мой случай. Растения у меня в квартире прошли некий естественный отбор, выжили самые неприхотливые, для которых полив +/- несколько дней особой роли не играет.
    3.Просто хочется, чтобы был датчик влажности. Вот хочется и всё тут!
     
  18. EandV

    EandV Нерд

    Кстати, если уж ставить датчики, то точно не с медью. Пишут, что через пару месяцев их коррозия убивает. Делают из нержавейки, но они тоже не вечные. Еще как вариант на графите из сердечников батареек. Но сейчас в моде емкостные, который как раз DIYMan предложил.
    Кстати датчик еще потребляет ток, около 5мА, что для автономных систем в плюс не идет. Моя система, для сравнения, в режиме ожидания потребляет 3мА. У меня в комнате 8 растений. Если я их все датчиками утыкаю, про автономность можно вообще забыть.
     
  19. DIYMan

    DIYMan Гуру

    Религией не запрещается подавать питание на датчик перед замером, и убирать - между замерами ;)
     
  20. EandV

    EandV Нерд

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