Часы и датчик дождя - правильный алгоритм для полива

Дык, учусь только. Зелёный ещё.

И диоду на 13 пине никогда не суждено загореться (или погаснуть, смотря как подключен)))

ИМХО, в этом проекте главный вопрос не в том, как включать реле, а в том, как правильно определить наличие/отсутствие дождя и его интенсивность.
Может накрапывать целый день, но земля так и не промокнет, при этом датчик будет рассказывать, что дождь , и обратная ситуация, за 10 минут выпадет месячная норма осадков, после которой поливать неделю не нужно.

1 лайк

Тут только воронка и чашка-качалка в будке. В противном случае проще с яндекс-погоды дёргать статус.

1 лайк

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

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

Раз мы уже про язык, то с целью повышения образованности:
if (tm.Hour >= h1 && tm.Hour < h2)
Так выполнит?

Если про язык, то это правильная запись условия “Х лежит между…”.
А выполнит или нет - записит от остального кода.

Сразу видно человека в теме! Респект! Я ничего умнее поплавкового датчика типа “пробка в консервной банке” не придумал. В жаркую погоду выливаю на газон 20 мм в неделю и не парюсь. В прохладное время дозу снижаю. Банка подсказывает сколько мм выпало с неба на халяву. А все эти датчики мокроты - ересь

2 лайка
#include <Wire.h>
#include <TimeLib.h>
#include <DS1307RTC.h>

int RelayPin1 = 12; // контакт с подключенным реле, контакты NO, иммитация кнопки "Пуск" на пускателе
int RelayPin2 = 11; // контакт с подключенным реле, , контакты NC, иммитация книпки "Стоп" на пускателе
int relay_time = 4000; // 4000 - 4 секунды
int RainPin = 9;  // подключается цифровой выход датчика дождя
int PowerRainPin = 10;  // контакт для питания датчика дождя
uint8_t h1 = 11; // час включения
uint8_t h2 = 16; // час выключения
uint8_t m1 = 5; // минуты включения
uint8_t m2 = 45; // минуты выключения
unsigned int on_water_time;
unsigned int off_water_time;
unsigned int time_rtc;


void setup() {
  Serial.begin(9600);
  while (!Serial);
  delay(200);
  pinMode(RelayPin1, OUTPUT);
  pinMode(RelayPin2, OUTPUT);
  digitalWrite(RelayPin1, HIGH);
  digitalWrite(RelayPin2, HIGH);
  pinMode(RainPin, INPUT);
  pinMode(PowerRainPin, OUTPUT);
  digitalWrite(PowerRainPin, LOW);
}


void loop() {
  int val = readSensor();
  tmElements_t tm;
  
  if (RTC.read(tm)) {
    print2digits(tm.Hour);
    Serial.write(':');
    print2digits(tm.Minute);
    Serial.write(':');
    print2digits(tm.Second);
    Serial.println();
   }

on_water_time = h1 * 60u + m1; //время включения в минутах
off_water_time = h2 * 60u + m2;//время выключения
time_rtc = tm.Hour * 60u + tm.Minute; //время с DS3231 в минутах

   
if (val == HIGH){
  if (time_rtc >= on_water_time && time_rtc <= off_water_time) {
    Relay1();
  }
  else {
    Relay2();
  }
}
else {
  Relay2(); 
}


  delay(1000);
}


void Relay1() {
  digitalWrite(RelayPin1, LOW);
  delay(relay_time);
  digitalWrite(RelayPin1, HIGH);
}

void Relay2() {
  digitalWrite(RelayPin2, LOW);
  delay(relay_time);
  digitalWrite(RelayPin2, HIGH);
}


void print2digits(int number) {
  if (number >= 0 && number < 10) {
    Serial.write('0');
  }
  Serial.print(number);
}


int readSensor() 
{
  digitalWrite(PowerRainPin, HIGH);   // включить датчик
  delay(10);                         // дать время питанию установиться
  int val = digitalRead(RainPin);  // прочитать выходной сигнал датчика
  digitalWrite(PowerRainPin, LOW);    // выключить датчик
  return val;                        // вернуть значение
}

Обновил код.
Если не сработал датчик дождя (val == HIGH), тогда проверка:
если время с DS3231 в минутах больше или равно времени включения и меньше или равно времени выключения, тогда сработает реле 1 (включит полив).
Иначе сработает реле 2 (отключит).
Если сработал датчик дождя, то сработает реле 2 (отключит).

Чудно как то обновили. Так нормально работать не будет.
Нужно убрать delay(relay_time);.
Т. е если условие включения реле выполняется, то вкл. если не выполняется - то выкл. И никаких делеев не надо.

P.S. Возможно я не прав. У Вас скорее используется магнитный
пускатель, тогда другое дело

Это в функциях. Реле не постоянно подключены. Relay1() - реле, контакты подключены параллельно кнопке “Пуск” на пускателе. Relay2() - реле, контакты подключены последовательно кнопке “Стоп” на пускателе. Они таким образом вк/выкл. пускатель.
Так у меня сейчас работает, включает и выключает по времени (без датчика дождя). На данный момент благодаря delay(relay_time), одно реле на несколько секунд срабатывает утром, второе вечером.
С добавлением датчика дождя уже в любом случае отпадает такая функция. Ведь сейчас, полив включается утром, я могу придти и нажать на пускателе кнопку “Стоп” и что-то там поделать. Когда закончу, нажимаю кнопку “Пуск” и ухожу, а вечером пускатель сам отключится с помощью реле и функции Relay2().
С добавлением датчика дождя, теперь мониторинг будет проходить чаще и контакты этих реле будут просто без смысла клацать. Есть наверное смысл, оставить одно реле: реле сработало - пускатель запустился, выключилось - пускатель выкоючится.

Да, пускатель.

Да, понял это. Схемы то нет…

Используйте флаг. Т.е. начало выполнения условия для вкл. полива - сработало реле и подняли флаг. И реле больше не трогаем, пока не будет условия для выкл. полива

1 лайк

Вот это точно, спс. Будут типа триггеров.

Такой вопрос на будущее. Я смотрю через уарт иногда, как тикает время. Когда приходит время (4 сек) выполнения функций Relay1() и Relay2(), данные на порту это время не отображаются. Я про это читал, советуют использовать millis ().
Не хочу я милис, если я буду данные отправлять на OLED дисплей, у меня не будет задержек в отображении времени?

Делей блокирует работу процессора. В это время ничего больше не происходит, (разве только с костылями типа yield(), но я это не применял)

1 лайк

Без millis везде будет задержка.

1 лайк
.................
bool flag = false;
void loop() {
  int val = readSensor();
  tmElements_t tm;
  
  if (RTC.read(tm)) {
    print2digits(tm.Hour);
    Serial.write(':');
    print2digits(tm.Minute);
    Serial.write(':');
    print2digits(tm.Second);
    Serial.println();
   }
 Serial.print("Rain: ");
 if (val == 1){
  Serial.println("No");
 }
 if (val == 0){
  Serial.println("Yes");
 }
 Serial.print("Flag: ");
 Serial.println(flag); // Выводим цифровое значение

on_water_time = h1 * 60u + m1; //время включения в минутах
off_water_time = h2 * 60u + m2;//время выключения
time_rtc = tm.Hour * 60u + tm.Minute; //время с DS3231 в минутах

   
if (val == HIGH){
  if (time_rtc >= on_water_time && time_rtc < off_water_time) {
    if (flag == false){
     Relay1(); 
    }
    
  }
  else {
    if (flag == true){
     Relay2();  
    }
    
  }
}
else {
  if (flag == true){
   Relay2();  
  }
  
}


  delay(1000);
}


void Relay1() {
  digitalWrite(RelayPin1, LOW);
  delay(relay_time);
  digitalWrite(RelayPin1, HIGH);
  flag = true;
}

void Relay2() {
  digitalWrite(RelayPin2, LOW);
  delay(relay_time);
  digitalWrite(RelayPin2, HIGH);
  flag = false;
}


void print2digits(int number) {
  if (number >= 0 && number < 10) {
    Serial.write('0');
  }
  Serial.print(number);
}


int readSensor() 
{
  digitalWrite(PowerRainPin, HIGH);   // включить датчик
  delay(10);                         // дать время питанию установиться
  int val = digitalRead(RainPin);  // прочитать выходной сигнал датчика
  digitalWrite(PowerRainPin, LOW);    // выключить датчик
  return val;                        // вернуть значение
}

Добавил фраг bool flag = false;
Реле когда срабатывают, записывают своё состояние флага.
Когда срабатывает логический оператор, там проверяется состояние флага и если оно отличается, то соответствующее реле клацает своими контактами.

1 лайк

Хорошо!

Начались дожди и выявилась одна неприятность. После того, как дождь заканчивается, устройство включается, но где-то спустя 10-30 секунд выключается. Так может происходить по 2-3 раза, после окончания дождя. Я так понимаю, это капли какие-то скатываются или по плате, или с дерева (рядом деревья), в общем устройство то включается, то выключается. Не хотелось бы этого.
Думаю нужно поставить задержку после выключения, минут на 3-5. За это время все эти срабатывания не будут учитываться.

void Relay2() {
  digitalWrite(RelayPin2, HIGH);
  delay(relay_time);
  digitalWrite(RelayPin2, LOW);
  flag = false;
  delay(300000); // ждёт 5 минут (300 секунд)
}

Добавил в функцию нажатия кнопки “Стоп”.
Или может какие есть другие решения?

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

1 лайк