Умный полив огорода №100500 (дневник полного 0 в мире Arduino)

NinoZombie
Offline
Зарегистрирован: 11.03.2018

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

Немного предыстории:
Краткость не моя сестра :)
Мне 23, живу в Иркутске. По образованию программист (но сфера деятельности совсем иная и программирование теперь только как хобби), огороды на дух не переносил всю жизнь :) Тут пришло время уже без "мам и пап" ездить на дачу и выращивать свои МЕГАнатуральный и МЕГАполезные овощи.
Больше всего не льстит мне необходимость постоянно, пусть даже раз в неделю, ездить на огород, тратить драгоценные дни лета, чтобы поливать всё вовремя.
Зато возможность освоить новое для себя направление очень интересна :)

С ардуинами и прочими сатанинскими штуками микроконтроллерами дела раньше никогда не имел. Пайка на уровне начальной школы, радиофизика опять же на уровне школьных теоретических знаний (можно сказать полный 0) :)

ЗАДАЧА и условия:
Полив огорода хочу осуществлять с использованием капельных лент . Потому что водопровода нет, но есть на возвышенной части участка половина ЖД цистерны воды (35 м3, высота над уровнем грядок около 5 метров), соответственно лучше всего подходят самотечные системы.
Поливать необходимо по таймеру (энергонезависимому), в дождь необходимо поливы пропускать для экономии воды. В случае сильной жары и засухи время полива увеличить.
Вся система должна выйти до 10000 рублей.

НАЧАЛЬНЫЙ ЭТАП:
Как я понял, разным растениям требуется разное количество воды, но на начальном этапе я на это решил забить. Взял норму ~ 2 литра в день. Составил небольшую схему участка и прикинул, что мне нужно около 200 литров в день выливать на растения (так как приблизительная пропускная способность одной щели в капельной ленте ~2 литра в час, а растений около 100).

Посчитал сколько денег уйдет на магистрали (40м), капельную ленту (85~100м), фильтр тонкой очистки (чтобы щели в ленте не забивались), фиттинги (стартовые, соединительные) и заглушки. Получилось около 4000 рублей. Пока укладываемся.

Что заказал на Алиэкспрессе в качестве компонентов для нашего "мозгового центра" (от одного продавца, чтобы было удобнее):
1) Arduino NANO https://ru.aliexpress.com/item/Freeshipping-Nano-3-0-controller-compatible-for-arduino-nano-CH340-USB-driver-NO-CABLE/32341832857.html?spm=a2g0s.9042311.0.0.ncirCD
2) Шилд расширительный для него (такая платка, куда будет втыкаться сам НАНО, чтобы было удобно к нему цеплять все модули) и макетную плату, чтобы проще было "на столе" это собрать для проб и тестов.
3) Модули датчиков (измеритель температуры и влажности воздуха, датчик дождя, датчик влажности почвы). Не факт, что всё это будет задействовано, но попробовать интересно :) Уже увидел, что датчик влажности почвы долго не живет под нагрузкой, а начинает сильно окисляться, поэтому морально готов делать из нержавейки и гипса свой такой щуп.
4) Провода макетные всякие разные, блок питания 9В 1А и клип для подключения питания от кроны (на самом деле больше был нужен просто штекер дополнительный, на всякий случай)
5) Шилд дисплея с кнопками (ну на всякий случай. Вдруг чего подредактировать на месте нужно будет или вручную систему запустить) и энергонезависимый модуль часов (чтоб при отключении энергии таймер не сбрасывался)
6) Насосик аквариумный для домашних тестов
7) Модуль реле и модуль повышатель напряжения (на случай, если не получится сдружиться с низковольтными насосами и клапанами)

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

ВОПРОС №1:
Из-за никакого уровня знаний в радиоэлектронике, встал вопрос. Будет ли у меня сигнал с датчиков доходить до ардуины, если их расположить в 20 метрах от неё? Понимаю, что будут помехи всякие и вообще сигнал слабенький, поэтому будет теряться... Но нельзя ли решить проблему использованием экранированной витой пары для соединения модуля и контроллера?
 

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

За 10 т.р.на Али можно купить готовый с кучей функций.
Сам сейчас делаю тупо таймер включения насоса полива по дням недели и по времени
Хотел замлрочиться капельным методом - жена сразу спросила а че будет если микро дырки шланга забьются...
В итоге дешевле за 300 рублей поставить разбрвзгиватель и включать воду на нужное время.

Aleks74
Offline
Зарегистрирован: 11.03.2018

Актуальный и интересный проект, буду следить за дневником!
А не было мысли использовать GSM модуль для управления поливом с телефона?

Jeka_M
Jeka_M аватар
Offline
Зарегистрирован: 06.07.2014

andycat пишет:
Хотел замлрочиться капельным методом - жена сразу спросила а че будет если микро дырки шланга забьются...

Ничего не будет, дырки так сильно не забиваются (или вообще не забиваются). На фермерских полях их расточительно используют - каждый год новые (фактически одноразовое использование). Хотя я уже несколько сезонов использую одни и те же капельные ленты. Всё нормально, ничего не забивается. Есдинственный нюнас - иногда ленты рвутся (на изгибах) и прокалываются. Но у меня не насос, а к водопроводу подключено. Остаётся только открывать/закрывать краник.

NinoZombie
Offline
Зарегистрирован: 11.03.2018

andycat пишет:
За 10 т.р.на Али можно купить готовый с кучей функций. Сам сейчас делаю тупо таймер включения насоса полива по дням недели и по времени Хотел замлрочиться капельным методом - жена сразу спросила а че будет если микро дырки шланга забьются... В итоге дешевле за 300 рублей поставить разбрвзгиватель и включать воду на нужное время.

Не могли бы Вы скинуть ссылку на подобное? Видел только какие-то таймерные клапаны (около 1500 руб. кажется), но там нет никаких "наворотов" вроде ориентирования по влажности почвы и дождю. Видел даже с датчиком.

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

NinoZombie
Offline
Зарегистрирован: 11.03.2018

Aleks74 пишет:
Актуальный и интересный проект, буду следить за дневником! А не было мысли использовать GSM модуль для управления поливом с телефона?

Спасибо за проявленный интерес :)
Одна беда - нет возможности стартовый пост редактировать. Поэтому когда всё будет готово придется переносить всю информацию в другую тему, чтобы всё в куче было.

Мысль использовать GSM модуль была. Единственное применение, которое я ему нашел, это использование в связке с модулем с SD картой в качестве системы для снятия отчетов, чтобы убеждаться, что всё работает в штатном режиме: например отправил смс-ку "отчет N", а контроллер тебе в ответ даты и время последних N поливов скидывает.
Ну и дальше если мысль развивать, то можно воткнуть датчик расхода воды в эту систему, чтобы еще и затраты воды показывал (всё таки запас ограничен).

NinoZombie
Offline
Зарегистрирован: 11.03.2018

NinoZombie пишет:
Что заказал на Алиэкспрессе в качестве компонентов для нашего "мозгового центра" (от одного продавца, чтобы было удобнее):

1) Arduino NANO https://ru.aliexpress.com/item/Freeshipping-Nano-3-0-controller-compatible-for-arduino-nano-CH340-USB-driver-NO-CABLE/32341832857.html?spm=a2g0s.9042311.0.0.ncirCD
2) Шилд расширительный для него (такая платка, куда будет втыкаться сам НАНО, чтобы было удобно к нему цеплять все модули) и макетную плату, чтобы проще было "на столе" это собрать для проб и тестов.
3) Модули датчиков (измеритель температуры и влажности воздуха, датчик дождя, датчик влажности почвы). Не факт, что всё это будет задействовано, но попробовать интересно :) Уже увидел, что датчик влажности почвы долго не живет под нагрузкой, а начинает сильно окисляться, поэтому морально готов делать из нержавейки и гипса свой такой щуп.
4) Провода макетные всякие разные, блок питания 9В 1А и клип для подключения питания от кроны (на самом деле больше был нужен просто штекер дополнительный, на всякий случай)
5) Шилд дисплея с кнопками (ну на всякий случай. Вдруг чего подредактировать на месте нужно будет или вручную систему запустить) и энергонезависимый модуль часов (чтоб при отключении энергии таймер не сбрасывался)
6) Насосик аквариумный для домашних тестов
7) Модуль реле и модуль повышатель напряжения (на случай, если не получится сдружиться с низковольтными насосами и клапанами)


Забыл сразу дописать. Все эти прибамбасы вышли ровно на 1000 рублей (купон какой-то там применился на $4)

Ну и, товарищи, заранее попрошу как можно меньше разговоров не по теме... Очень потом сложно в зафлуженных проектах ориентироваться, на себе уже проверил :)

Если кто ответ на вопрос знает, то слезно умоляю посвятить в решение! Пока только на нём затыки :( Вижу, что очень много людей для теплиц такой проект делали, но там ведь расстояния не такие...

NinoZombie пишет:
ВОПРОС №1:
Из-за никакого уровня знаний в радиоэлектронике, встал вопрос. Будет ли у меня сигнал с датчиков доходить до ардуины, если их расположить в 20 метрах от неё? Понимаю, что будут помехи всякие и вообще сигнал слабенький, поэтому будет теряться... Но нельзя ли решить проблему использованием экранированной витой пары для соединения модуля и контроллера?

 

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

Новая автоматическая Интеллектуальный электронный Сад Вода Таймер орошения спринклерной САД контроллер ЖК-дисплей бытовой полива устройства
http://s.aliexpress.com/6NnMvqY3?fromSns=Copy to Clipboard

Вот например, видел ещё похожую с датчиком дождя, выбор ьольшой

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

Фильтр в огороде рядом с землей не поможет так как даже при сборке все равно что то в шланг попадает, впрочем не пробовал капельную систему - спорить не буду.
И у меня в требованиях (жены) основное это полив в определённые дни на определённое время, потому и выбрал брызгалку круговую или сектору.
И кстати я не очень понял что подразумевается водопровод есть или нет? Разница в чем? Если водопровод - клапан по таймеру, если скважина (как у меня) или колодец включение насоса.

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

Вот ещё нашёл с датчиком дождя

Два выхода сад цифровой таймер автоматического водяного электромагнитный Клапан полива сада таймер 21060 и дождя Сенсор 21103 # 21060r
http://s.aliexpress.com/aumeQZnY?fromSns=Copy to Clipboard

bwn
Offline
Зарегистрирован: 25.08.2014

NinoZombie пишет:

ВОПРОС №1:
Из-за никакого уровня знаний в радиоэлектронике, встал вопрос. Будет ли у меня сигнал с датчиков доходить до ардуины, если их расположить в 20 метрах от неё? Понимаю, что будут помехи всякие и вообще сигнал слабенький, поэтому будет теряться... Но нельзя ли решить проблему использованием экранированной витой пары для соединения модуля и контроллера?

Прежде, чем начинать решать проблему надо ее поиметь. В вашем списке, кроме DHT11 (лучше вообще с ним не связывайтесь, хоть DHT22), датчики имеют бинарный выход (установили порог и он дает ноль или единицу), а эти значения ловятся достаточно легко и мало подвержены внешним влияниям. На дальнее расстояние просится только датчик влажности почвы остальные таскать нет смысла. 
Теперь о главном, проблема придет откуда не ждали, а конкретно от вашей идеи схемотехники (сборка из шилдов), рекомендую сразу записать ее в еретические, сделать публичное аутодафе и развеять пепел над форумом. Хотите нормальной работы, осваивайте ЛУТ, делайте платы и боевой девайс делайте на них. ИМХО.

sadman41
Offline
Зарегистрирован: 19.10.2016

Кстати, по поводу огородов. Была у меня идея срастить Xiaomi Flora Monitor (https://mysku.ru/blog/china-stores/43295.html) c ардуиной. Но не вышло - не нашел БТ-модуль, в котором реализован полностью GATT. А без него не работает конструкция. Однако, если завязаться с RaspberryPi или её клонами, то можно к их линупсу приделать обычный БТ свисток и GATT получить уже внутри ОС. Таким образом мы имеем чуть больше геморроя, но функционал явно вырастает. Конечно, если эти волшебные китайские штуки не будут тырить соседи. Ежели дом свой и тепличка, то вообще проблем нет, наверное. Конечно я понимаю, что по правильному нужно из натыкать через каждый метр почвы...

Сам датчик неплохой, за полтора года не обгнил, батарейку не менял еще. Протокол более-менее похачен.. С айфоном через две бетонные стены коммуницирует.

Это так, в качестве идеи.

Andrey12
Andrey12 аватар
Offline
Зарегистрирован: 26.12.2014

Да тема интересная подпишусь.

NinoZombie пишет:

фильтр тонкой очистки (чтобы щели в ленте не забивались)

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

NinoZombie пишет:

3) Модули датчиков (измеритель температуры и влажности воздуха, датчик дождя, датчик влажности почвы). Не факт, что всё это будет задействовано, но попробовать интересно :) Уже увидел, что датчик влажности почвы долго не живет под нагрузкой, а начинает сильно окисляться, поэтому морально готов делать из нержавейки и гипса свой такой щуп.

DHT11 и иже с ним сразу в мусорку, выше уже писали почему. Смотрите в сторону Si7021 или BME280. Датчик влажности только емкостной, ну или если есть желание пройти по граблям уже пройденным многими, то конечно можно начать с того что вы указали.

NinoZombie пишет:

5) Шилд дисплея с кнопками (ну на всякий случай. Вдруг чего подредактировать на месте нужно будет или вручную систему запустить) и энергонезависимый модуль часов (чтоб при отключении энергии таймер не сбрасывался)

Ну тут тоже на вкус и цвет, проще энкодер и ОЛЕД дисплей, в принципе OLED форм фактора 2004 и 1602 тоже сейчас есть, из плюсов в них графический режим и поддержка русского языка.

NinoZombie пишет:

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

Лучше шаровый кран с моторчиком, да дороже, но у вас самотёк, через этот клапан ничего толком не протечет без давления.

NinoZombie пишет:

ВОПРОС №1:
Из-за никакого уровня знаний в радиоэлектронике, встал вопрос. Будет ли у меня сигнал с датчиков доходить до ардуины, если их расположить в 20 метрах от неё? Понимаю, что будут помехи всякие и вообще сигнал слабенький, поэтому будет теряться... Но нельзя ли решить проблему использованием экранированной витой пары для соединения модуля и контроллера?

Ну для этого и есть цифра, ставите Si7021 и P82B715 I2C Bus Extender или используете RS485 и будет вам счастье.

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

В продолжение темы полива огорода, закончил таймер включения насоса,

Arduino Pro Mini, DS1307, два БП и реле, индикатор,

7 светодиодов отображают выбраные дни полива, 4х разрядный 7и сегментный индикатор

отображает в время полива, длительность полива в минутах.


// street pump for Arduino pro mini 5v

#include <TM1637.h>
#include <RTClib.h>
#include <EEPROM.h>
#include <avr/wdt.h>

uint8_t mcusr_mirror __attribute__ ((section (".noinit")));
void get_mcusr(void) \
__attribute__((naked)) \
__attribute__((used)) \
__attribute__((section(".init3")));
void get_mcusr(void)
{
  mcusr_mirror = MCUSR;
  MCUSR = 0;
  wdt_disable();
}

#define count_keys 5
#define start_pin_keys 2

#define pos_eeprom_min_pump 19
#define pos_eeprom_hour_time 20
#define pos_eeprom_min_time 21
#define pos_eeprom_stat_days 22 // 7 bytes 0-off 1=on Monday....Sunday

#define period_read_key 100UL
#define min_count_key_down 2

#define max_time_options 10000UL // 10 sec

#define period_flash_led_days 50UL

#define period_get_real_time 60000UL // 1 min

byte tmPoint = 0;

unsigned long timer_get_real_time = 0;
unsigned long timer_read_key = 0;
unsigned long timer_every_sec = 0;
unsigned long timer_flash_led_days;
unsigned long timer_time_options;
unsigned long timer_pumping;

byte keys_down[count_keys];
byte keys_begin[count_keys];
byte keys_click[count_keys];

boolean startFlashLedDays = false;
byte currentFlashLedDays;
byte nextFlashLedDays;

TM1637 mytm(1, 0); // TM1637 0-CLK 1-DIO
RTC_DS1307 myrtc; // DS1307 A4-SDA A5-SCL

byte daysWeek[7]; // 1-day enable 0-day disable
byte minPump; // period for pumping by min
byte hourTime; // hour for pump
byte minTime; // min for pump

byte deviceMode = 0;
// 0 - main mode
// 1 - set day pump
// 2 - set period min pumping
// 3 - set real time on DS1307
// 4 - pumping

byte currentDay; // current day of week from 0 = monday
byte currentHour; // current hour of day
byte currentMin; // current min of hour

void setup() {
  // put your setup code here, to run once:
  for (byte i = 17; i >= 11; --i) { // init led Monday....Sunday, A3...A0 D13...D11 and OFF
    pinMode(i, OUTPUT); digitalWrite(i, HIGH);
  }
  pinMode(0, OUTPUT); digitalWrite(0, LOW); // CLK TM1637 display
  pinMode(1, OUTPUT); digitalWrite(1, LOW); // DIO TM1637 display
  pinMode(2, INPUT); digitalWrite(2, HIGH); // key select day pump / set day real time
  pinMode(3, INPUT); digitalWrite(3, HIGH); // key set day pump / set month real time
  pinMode(4, INPUT); digitalWrite(4, HIGH); // key select time hour pump / set hour real time
  pinMode(5, INPUT); digitalWrite(5, HIGH); // key select time min pump / set min real time
  pinMode(6, INPUT); digitalWrite(6, HIGH); // key select period min pump / set year real time
  pinMode(7, OUTPUT); digitalWrite(7, LOW); // OFF relay pump
  pinMode(8, OUTPUT); digitalWrite(8, LOW); // OFF reserv relay
  pinMode(9, OUTPUT); digitalWrite(9, LOW); // off unused pin
  pinMode(10, OUTPUT); digitalWrite(10, LOW); // off unused pin
  pinMode(A6, OUTPUT); digitalWrite(A6, LOW); // off unused pin
  pinMode(A7, OUTPUT); digitalWrite(A7, LOW); // off unused pin
  if (! myrtc.begin())  while (1); // init DS1307
  mytm.init(); // init TM1637
  mytm.set(5); // BRIGHT TM1637 MAX=7
  mytm.point(0); mytm.display(0, 0x0A); mytm.point(1); mytm.display(1, 0x0B); mytm.point(0); mytm.display(2, 0x0C); mytm.point(1); mytm.display(3, 0x0D);
  unsigned long delp = millis(); while ((millis() - delp) <= 5000); // delay 5 sec for RTC
  mytm.point(1); mytm.display(0, 0x0E); mytm.point(0); mytm.display(1, 0x0F); mytm.point(1); mytm.display(2, 0x00); mytm.point(0); mytm.display(3, 0x09);
  delp = millis(); while ((millis() - delp) <= 10000); // delay 10 sec for RTC
  //myrtc.adjust(DateTime(2018, 3, 1, 12, 24, 10)); // test
  getCurrentTime(); // load day and time from DS1307
  showCurrentTimeAndDay();
  loadDataFromEeprom();
  for (byte i = 0; i < count_keys; ++i) keys_begin[i] = 0; // reset keys
  wdt_enable(WDTO_4S);
  delp = millis(); while ((millis() - delp) <= 1000); // delay 1 sec fo test
}

void loop() {
  wdt_reset();
  // put your main code here, to run repeatedly:
  //delay(5000); // test wdt
  unsigned long current_millis = millis();
  // get current time every 1 min
  if ((current_millis - timer_get_real_time) >= period_get_real_time) {
    timer_get_real_time = current_millis;
    getCurrentTime();
    // compare time and day for start pumping
    if ((currentHour == hourTime) && (daysWeek[currentDay] == 1) && ((currentMin - minTime) >= 0) && ((currentMin - minTime) <= 4) && (deviceMode == 0)) {
      timer_pumping = current_millis;
      deviceMode = 4;
    }
  }
  // end timer options
  if ((deviceMode > 0) && (deviceMode < 4)) {
    if ((current_millis - timer_time_options) >= max_time_options) {
      deviceMode = 0;
    }
  }
  // operate keys
  if ((current_millis - timer_read_key) >= period_read_key) {
    timer_read_key = current_millis;
    for (byte i = 0; i < count_keys; ++i) {
      if (digitalRead(i + start_pin_keys) == 0) {
        // key id down
        if (keys_begin[i] == 1) {
          ++keys_down[i];
        } else {
          keys_begin[i] = 1;
          keys_down[i] = 0;
          keys_click[i] = 0;
        }
      } else {
        // key is up
        if (keys_begin[i] == 1) {
          if (keys_down[i] >= min_count_key_down) {
            // short click
            keys_begin[i] = 0;
            keys_down[i] = 0;
            keys_click[i] = 1;
          } else {
            // no click
            keys_begin[i] = 0;
            keys_down[i] = 0;
            keys_click[i] = 0;
          }
        }
      }
    }
    // analize keys
    if (keys_click[0] == 1) {
      if (deviceMode == 0) {
        timer_time_options = current_millis;
        deviceMode = 1;
        currentFlashLedDays = 0;
      } else if (deviceMode == 1) {
        timer_time_options = current_millis;
        if ((++currentFlashLedDays) > 6) currentFlashLedDays = 0;
      }
    }
    if (keys_click[1] == 1) {
      if (deviceMode == 1) {
        if (daysWeek[currentFlashLedDays] == 1) daysWeek[currentFlashLedDays] = 0; else daysWeek[currentFlashLedDays] = 1;
        EEPROM.update((currentFlashLedDays + pos_eeprom_stat_days), daysWeek[currentFlashLedDays]);
      }  else if (deviceMode == 0) {
        showCurrentTimeAndDay();
      }
    }
    if ((keys_click[2] == 1) && (deviceMode == 0)) {
      if ((++hourTime) > 23) hourTime = 5;
      EEPROM.update(pos_eeprom_hour_time, hourTime);
      showStartTimePumpAndPoint();
    }
    if ((keys_click[3] == 1) && (deviceMode == 0)) {
      if ((minTime += 5) > 55) minTime = 0;
      EEPROM.update(pos_eeprom_min_time, minTime);
      showStartTimePumpAndPoint();
    }
    if (keys_click[4] == 1) {
      if (deviceMode == 0) {
        timer_time_options = current_millis;
        deviceMode = 2;
        mytm.clearDisplay();
        showPeriodTimePump();
      } else if (deviceMode == 2) {
        timer_time_options = current_millis;
        if ((minPump += 5) > 30) minPump = 5;
        EEPROM.update(pos_eeprom_min_pump, minPump);
        showPeriodTimePump();
      }
    }
    // end analize keys
  }
  // flash days led every 1 sec and othen action every sec
  if ((current_millis - timer_every_sec) >= 1000UL) {
    timer_every_sec = current_millis;
    timer_flash_led_days = current_millis;
    startFlashLedDays = true;
    nextFlashLedDays = 0;
    // other actions every sec
    if (deviceMode == 0) {
      // show start pump time and flash point
      showStartTimePumpAndPoint();
    }
    if (deviceMode == 4) {
      if (((current_millis - timer_pumping) <= (minPump * 60000UL)) && (minPump < 40)) {
        digitalWrite(8, HIGH); // reserv ON
        unsigned long delp = millis(); while ((millis() - delp) <= 300);
        digitalWrite(7, HIGH); // pump ON
        showTimePumping((current_millis - timer_pumping) / 1000);
      } else {
        digitalWrite(7, LOW); // pump OFF
        unsigned long delp = millis(); while ((millis() - delp) <= 300);
        digitalWrite(8, LOW); // reserv OFF
        deviceMode = 0;
      }
    } else {
      digitalWrite(7, LOW); // pump OFF
      digitalWrite(8, LOW); // reserv OFF
    }
    if (deviceMode != 1) {
      // ON led active days
      for (byte i = 0; i <= 6; ++i) if (daysWeek[i] == 1) digitalWrite((17 - i), LOW); // led on
    }
    // other actions every sec
  }
  // flash days leds
  if ((current_millis - timer_flash_led_days) >= period_flash_led_days) {
    timer_flash_led_days = current_millis;
    if (startFlashLedDays) {
      if (deviceMode != 1) {
        byte workled = 99;
        if (nextFlashLedDays == 0) {
          // begin loop
          // nothing off led
          // find first free led
          for (byte i = 0; i <= 6; ++i) {
            if (daysWeek[i] == 0) {
              workled = i;
              break;
            }
          }
          if (workled <= 6) {
            digitalWrite((17 - workled), LOW); // led on
          } else {
            startFlashLedDays = false;
          }
          currentFlashLedDays = nextFlashLedDays;
          ++nextFlashLedDays;
        } else {
          // off current led
          if ((currentFlashLedDays > 0) || ((daysWeek[0] == 0) && (currentFlashLedDays == 0)))
            digitalWrite((17 - currentFlashLedDays), HIGH); // led off
          if (nextFlashLedDays > 6) {
            startFlashLedDays = false;
          } else {
            // find first free led
            for (byte i = nextFlashLedDays; i <= 6; ++i) {
              if (daysWeek[i] == 0) {
                workled = i;
                break;
              }
            }
            if (workled <= 6) {
              digitalWrite((17 - workled), LOW); // led on
              currentFlashLedDays = workled;
              nextFlashLedDays = (workled + 1);
            } else {
              startFlashLedDays = false;
            }
          }
        }
      } else {
        // flash for set day pump mode
        // currentFlashLedDays - is current select day by user
        for (byte i = 0; i <= 6; ++i) {
          if (i == currentFlashLedDays) {
            if (nextFlashLedDays == 0) {
              if (daysWeek[i] == 1) digitalWrite((17 - i), HIGH); else digitalWrite((17 - i), LOW);
              ++nextFlashLedDays;
            } else {
              if (daysWeek[i] == 1) digitalWrite((17 - i), LOW); else digitalWrite((17 - i), HIGH);
              startFlashLedDays = false;
            }
          } else {
            if (daysWeek[i] == 1) digitalWrite((17 - i), LOW); else digitalWrite((17 - i), HIGH);
          }
        }
      }
    }
  }
  // end loop
  // clear keys
  for (byte i = 0; i < count_keys; ++i) keys_click[i] = 0;
  // --
}

void getCurrentTime() {
  DateTime now = myrtc.now();
  currentHour = now.hour();
  currentMin = now.minute();
  currentDay = now.dayOfTheWeek();
  if (currentDay == 0) currentDay = 6; else --currentDay;
}

void loadDataFromEeprom() {
  minPump = EEPROM.read(pos_eeprom_min_pump);
  if ((minPump < 5) || (minPump > 30)) minPump = 5;
  hourTime = EEPROM.read(pos_eeprom_hour_time);
  if ((hourTime < 5) || (hourTime > 23)) hourTime = 5;
  minTime = EEPROM.read(pos_eeprom_min_time);
  if (minTime > 55) minTime = 0;
  for (byte i = 0; i <= 7; ++i)
      if (EEPROM.read(i + pos_eeprom_stat_days) == 1) daysWeek[i] = 1; else daysWeek[i] = 0;
}

void showStartTimePumpAndPoint() {
  mytm.point(0);
  mytm.display(0, (hourTime / 10));
  tmPoint = !tmPoint;
  mytm.point(tmPoint);
  mytm.display(1, (hourTime % 10));
  mytm.point(0);
  mytm.display(2, (minTime / 10));
  mytm.point(0);
  mytm.display(3, (minTime % 10));
}

void showPeriodTimePump() {
  mytm.point(0);
  tmPoint = !tmPoint;
  mytm.point(tmPoint);
  mytm.point(0);
  mytm.display(2, (minPump / 10));
  mytm.point(0);
  mytm.display(3, (minPump % 10));
}

void showTimePumping(word unTimePump) {
  mytm.point(0);
  mytm.display(0, (unTimePump / 60) / 10);
  tmPoint = !tmPoint;
  mytm.point(tmPoint);
  mytm.display(1, (unTimePump / 60) % 10);
  mytm.point(0);
  mytm.display(2, (unTimePump % 60) / 10);
  mytm.point(0);
  mytm.display(3, (unTimePump % 60) % 10);
}

void showCurrentTimeAndDay() {
  if ((currentDay > 0) && (currentDay < 4)) mytm.point(0); else mytm.point(1);
  mytm.display(0, (currentHour / 10));
  if ((currentDay == 0) || (currentDay == 2) || (currentDay == 3)) mytm.point(0); else mytm.point(1);
  mytm.display(1, (currentHour % 10));
  if ((currentDay == 2) || (currentDay == 5) || (currentDay == 6)) mytm.point(1); else mytm.point(0);
  mytm.display(2, (currentMin / 10));
  if ((currentDay == 3) || (currentDay == 6)) mytm.point(1); else mytm.point(0);
  mytm.display(3, (currentMin % 10));
}