Steuerung für Bewässerung / Ventile

Hi , ich baue gerade ein Bewässerungssteuerung für meinen Garten. Ich habe hierzu den Sketch von jurs aus dem Forum genommen und wollte ihn etwas erweitern.
zum Aufbau: Ich habe 2 Ventile ,eine Pumpe und einen "Regensensor" und eine RTC3231

Die Pumpe (Pin 4) soll von 20:30Uhr - 20:40 laufen
der Regensensor überprüft ob es geregnet hat oder nicht -> wenn ja dann sollen die Ventile (Pin 7+8) geschlossen bleiben
wenn es nicht geregnet hat, sollen die Ventile (Pin 7+8 ) zeitversetzt auf
Ventil 1 (Pin 7) 20:30 - 20:35 Uhr
Ventil 2 (Pin 8) 20:35 - 20:40 Uhr

Der Regensensor besteht einfach nur aus 2 Drähten die messen ob sich Wasser in einem kleinen Behälter befindet oder nicht, angeschlossen ist er auf Pin 9

Ich habe jetzt schon einiges Probiert aber war leider erfolglos . Vielleicht habt ihr ja eine Idee wie ich das umsetzen könnte. Vielleicht ist der Code von jurs aber einfach zu overkill für mein Vorhaben..was denkt ihr?

grüße Alex

#define EIN LOW
#define AUS HIGH

const int sensorPin = 9; //Pin D9
int sensorState = 0;

struct schaltRelais_t {
  byte pin;
  int ein1; int aus1;
  int ein2; int aus2;
  int ein3; int aus3;


};

// Hier die Relais-Pins definieren mit Ein- und Ausschaltzeiten
schaltRelais_t schaltRelais[3] = {
  {4, 2030, 2040,},  // Pumpe      Relais Pin, Einschaltzeit, Ausschaltzeit
  {7, 2030, 2035,}, // Ventil Beet 1
  {8, 2035, 2040,}, // Ventil Beet 2

};

void relaisSchaltenNachZeit(int thishour, int thisminute)
// Schaltet die Zeitschaltuhr ein und aus und setzt den Ausgang entsprechend
{
  boolean state;
  // Aus der aktuellen Zeit eine Schaltzeit bilden
  int thisTime = thishour * 100 + thisminute;
  // Alle Schaltzeiten durchgehen, falls eine davon EIN sagt, einschalten
  for (int i = 0; i < sizeof(schaltRelais) / sizeof(schaltRelais_t); i++)
  {
    state = AUS; // Amnahme: Es sei nichts geschaltet
    
    if (
      (thisTime >= schaltRelais[i].ein1 && thisTime < schaltRelais[i].aus1) ||
      (thisTime >= schaltRelais[i].ein2 && thisTime < schaltRelais[i].aus2) ||
      (thisTime >= schaltRelais[i].ein3 && thisTime < schaltRelais[i].aus3) 
    )
    {
      state = EIN;
    }
    if (digitalRead(schaltRelais[i].pin) != state) // Falls geschaltet werden soll
    { // ein paar Debug-Ausgaben machen
      Serial.print("Relais ");
      Serial.print(i + 1); // Relais-Index zählt ab 0, einfach 1 dazuzählen
      Serial.print(": ");
      if (state == EIN) Serial.println("EIN"); else Serial.println("AUS");
    }
        digitalWrite(schaltRelais[i].pin, state); // Schaltzustand setzen
  
}
}



#include <Wire.h>
// I2C Adresse der RTC ist 0x68 für DS1307 und DS3231
#define RTC_I2C_ADDRESS 0x68

int jahre, monate, tage, stunden, minuten, sekunden;
// wochentag bleibt in diesem Test-Sketch unberücksichtigt

void rtcReadTime(int &jahre, int &monate, int &tage, int &stunden, int &minuten, int &sekunden)
// aktuelle Zeit aus RTC auslesen
{
  // Reset the register pointer
  Wire.beginTransmission(RTC_I2C_ADDRESS);
  Wire.write(0);
  Wire.endTransmission();
  Wire.requestFrom(RTC_I2C_ADDRESS, 7);
  // A few of these need masks because certain bits are control bits
  sekunden    = bcdToDec(Wire.read() & 0x7f);
  minuten     = bcdToDec(Wire.read());
  stunden     = bcdToDec(Wire.read() & 0x3f);  // Need to change this if 12 hour am/pm
  /*wochentag   = */bcdToDec(Wire.read());
  tage        = bcdToDec(Wire.read());
  monate      = bcdToDec(Wire.read());
  jahre       = bcdToDec(Wire.read()) + 2000;
}

void rtcWriteTime(int jahre, int monate, int tage, int stunden, int minuten, int sekunden)
// aktuelle Zeit in der RTC speichern
{
  Wire.beginTransmission(RTC_I2C_ADDRESS);
  Wire.write(0);
  Wire.write(decToBcd(sekunden));    // 0 to bit 7 starts the clock
  Wire.write(decToBcd(minuten));
  Wire.write(decToBcd(stunden));      // If you want 12 hour am/pm you need to set
  // bit 6 (also need to change readDateDs1307)

  Wire.write(decToBcd(0)); // Wochentag unberücksichtigt
  Wire.write(decToBcd(tage));
  Wire.write(decToBcd(monate));
  Wire.write(decToBcd(jahre - 2000));
  Wire.endTransmission();
}

byte decToBcd(byte val) // Hilfsfunktion zum Lesen/Schreiben der RTC
// Convert decimal number to binary coded decimal
// Hilfsfunktion für die Echtzeituhr
{
  return ( (val / 10 * 16) + (val % 10) );
}

byte bcdToDec(byte val)  // Hilfsfunktion zum Lesen/Schreiben der RTC
// Convert binary coded decimal to decimal number
// Hilfsfunktion für die Echtzeituhr
{
  return ( (val / 16 * 10) + (val % 16) );
}


int getIntFromString (char *stringWithInt, byte num)
// input: pointer to a char array
// returns an integer number from the string (positive numbers only!)
// num=1, returns 1st number from the string
// num=2, returns 2nd number from the string, and so on
{
  char *tail;
  while (num > 0)
  {
    num--;
    // skip non-digits
    while ((!isdigit (*stringWithInt)) && (*stringWithInt != 0)) stringWithInt++;
    tail = stringWithInt;
    // find digits
    while ((isdigit(*tail)) && (*tail != 0)) tail++;
    if (num > 0) stringWithInt = tail; // new search string is the string after that number
  }
  return (strtol(stringWithInt, &tail, 10));
}


void setup()
{
  pinMode(sensorPin, INPUT);
  Wire.begin();       // initialisiert die Wire-Library
  Serial.begin(9600); // Serielle Kommunikation starten
  while (!Serial);    // wait for serial port to connect. Needed for Leonardo only
  Serial.println("\r\nZeitschaltuhr- und Kurzzeittimer-Demo Sketch");
  Serial.println("Coded by jurs for German Arduino Forum.");
  Serial.println("Jede Minute wird die aktuelle Zeit im 'Seriellen Monitor' angezeigt.");
  Serial.println("Ebenso alle Ein- und Ausschaltungen und die Kurzzeittimer-Aktion");
  Serial.println();
  Serial.println("Du kannst die Zeit mit einem 'set' Befehl im 'Serial Monitor' neu setzen.");
  Serial.println("\r\nBeispiel:");
  Serial.println("set 28.08.2013 10:54\r\n");
  for (int i = 0; i < sizeof(schaltRelais) / sizeof(schaltRelais_t); i++)
  {
    digitalWrite(schaltRelais[i].pin, AUS);
    pinMode(schaltRelais[i].pin, OUTPUT);
  }
}


void behandleSerielleBefehle()
{
  char linebuf[30];
  byte counter;
  if (Serial.available())
  {
    delay(100); // Warte auf das Eintreffen aller Zeichen vom seriellen Monitor
    memset(linebuf, 0, sizeof(linebuf)); // Zeilenpuffer löschen
    counter = 0; // Zähler auf Null
    while (Serial.available())
    {
      linebuf[counter] = Serial.read(); // Zeichen in den Zeilenpuffer einfügen
      if (counter < sizeof(linebuf) - 1) counter++; // Zeichenzähler erhöhen
    }
    // Ab hier ist die Zeile eingelesen
    if (strstr(linebuf, "set") == linebuf) // Prüfe auf Befehl "set" zum Setzen der Zeit
    { // Alle übermittelten Zahlen im String auslesen
      tage = getIntFromString (linebuf, 1);
      monate = getIntFromString (linebuf, 2);
      jahre = getIntFromString (linebuf, 3);
      stunden = getIntFromString (linebuf, 4);
      minuten = getIntFromString (linebuf, 5);
      sekunden = getIntFromString (linebuf, 6);
    }
    else
    {
      Serial.println("Befehl unbekannt.");
      return;
    }
    // Ausgelesene Werte einer groben Plausibilitätsprüfung unterziehen:
    if (jahre < 2000 || monate < 1 || monate > 12 || tage < 1 || tage > 31 || (stunden + minuten) == 0)
    {
      Serial.println(linebuf);
      Serial.println("\r\nFehlerhafte Zeitangabe im 'set' Befehl");
      Serial.println("\r\nBeispiel:");
      Serial.println("set 28.08.2013 10:54\r\n");
      return;
    }
    rtcWriteTime(jahre, monate, tage, stunden, minuten, sekunden);
    Serial.println("Zeit und Datum wurden auf neue Werte gesetzt.");
  }
}


void loop()
{
  char buffer[30];
  static unsigned long lastMillis;
  static int lastMinute;
  int stunden, minuten, sekunden, dummy;
  sensorState = digitalRead(sensorPin);
  if (millis() - lastMillis > 1000) // nur einmal pro Sekunde
  {
    lastMillis = millis();
    rtcReadTime(dummy, dummy, dummy, stunden, minuten, sekunden);
    if (minuten != lastMinute) // die aktuelle Minute hat gewechselt
    {
      lastMinute = minuten;
      snprintf(buffer, sizeof(buffer), "%02d:%02d Uhr", stunden, minuten);
      Serial.println(buffer);
      relaisSchaltenNachZeit(stunden, minuten);
    }
  }
  behandleSerielleBefehle();
}

Ihre Anforderungen sind unvollständig.

Wenn ich Sie richtig verstanden habe:

  • wenn der kleine Behälter leer ist
    Die Pumpe (Pin 4) sollte von 20:30 bis 20:40 Uhr laufen.
    Ventil 1 (Pin 7) 20:30 Uhr. - 20:35 Uhr.
    Ventil 2 (Pin 8) 20:35 - 20:40 Uhr

  • wenn der kleine Behälter nicht leer ist
    Die Pumpe (Pin 4) sollte von 20:30 bis 20:40 Uhr laufen.

aber wann prüfen Sie, ob der kleine Behälter leer ist oder nicht? (die ganze Zeit während des Betriebs? nur um 20:30 Uhr vor dem Einschalten der Pumpe? ...)

Hallo, so richtig verstehe ich nicht, wo dein Problem ist.
Beschreibe doch mal etwas genauer, was geht und was nicht geht.
Zu deinem Wassersensor hätte ich nicht viel Vertrauen. Den würde ich etwas anders aufbauen, damit auch langfristig eine sichere Auswertung gegeben ist. Verwende dazu einen NPN oder PNP-Transistor zur Verstärkung und gehe dann auf einen analogen Pin zur besseren Auswertung. Und wichtig dabei ist, verwende Edelstahldrähte, am besten aus V4A.

@ J-M-L
Ja genau, es müsste jeden tag um 20:30 geprüft werden ob Wasser im Behälter ist oder nicht.
es scheitert nur an der umsetzung :woozy_face:

@HotSystems
Also...Ich habe 2 Beete und ein Gewächshaus. Ich möchte die Bewässerung automatisieren. Dazu habe ich eine Pumpe und 2 Ventile. Wenn es geregnet hat befindet sich wasser in einem kleinen Behälter mit 2 V2A Drähten. Dort wird überprüft ob sich im Behälter Wasser befindet oder nicht.
Wenn es geregnet hat ,sollen die beiden Ventile zu bleiben und nur das Gewächshaus bewässert werden.( die Beete sind ja schon vom Regen nass). Wenn es nicht geregnet hat sollen die Ventile auf gehen und beide Beete + Gewächshaus bewässert werden. Erst soll das Gewächshaus+ Ventil1 5 min lang ab 20:30 UHr bewässert werden und danach von 20:35-20:40 nur das Beet 2.

wie würdest du das mit dem Transistor machen?

Ich poste dir später meine Schaltung die ich seit einigen Jahren für meine Drainagepumpensteuerung verwende. Und das problemlos.

Hallo,
dann messe den Sensor doch immer und entscheide um 2030 was zu tun ist.Das kann man mit if machen
in etwas sowas

if (thisTime >=2030 && thisTime <=2100 && Fuellstand== LOW){  // es hat nicht geregnet

// hier das was Du willst. z.B
   if ( thisTime >=2030 && tisTime <2035) digitalWrite(venil1,HIGH);
   else digitalWrite(ventil1,LOW);

}

mach doch einfach mal das Beispiel "simpleRTC" aus der lib und bau darauf auf.
Heinz

was haben Sie denn für eine RTC? Mit einem DS3231 können Sie jeden Tag um 20:30 Uhr einen Wecker stellen.

Hier meine Schaltung mit einem PNP-Transistor.
Wassersensor1_PNP
Über die Auswertung am analogen Pin ist eine Schaltschwelle sehr genau einstellbar.

Habe es jetz erstmal so gelöst. Sollte funktionieren.

//Bewässerungssteuerung 
//
//
//

#include <DS3231.h>
#include <Wire.h>
#define RTC_I2C_ADDRESS 0x68

int jahre, monate, tage, stunden, minuten, sekunden;
int ventil1 = 8;
int ventil2 = 7;
int pumpe = 4;
int sensor = 10;
int sensorState = 0;

const int OnHour = 20; //SET TIME TO ON RELAY (24 HOUR FORMAT)
const int OnMin = 30;
const int OffHour = 20; //SET TIME TO OFF RELAY
const int OffMin = 40;

DS3231  rtc(SDA, SCL);
Time t;


void setup() {
  Serial.begin(9600); // Serielle Kommunikation starten
  rtc.begin();
  pinMode(ventil1, OUTPUT);
  pinMode(ventil2, OUTPUT);
  pinMode(pumpe, OUTPUT);
  pinMode(sensor, INPUT);
  digitalWrite(ventil1, LOW);
  digitalWrite(ventil2, LOW);
  digitalWrite(pumpe, LOW);



//---------------------   

  Wire.begin();       // initialisiert die Wire-Library
  while (!Serial);    // wait for serial port to connect. Needed for Leonardo only
  Serial.println("\r\nZeitschaltuhr- und Kurzzeittimer-Demo Sketch");
  Serial.println("Coded by jurs for German Arduino Forum.");
  Serial.println("Jede Minute wird die aktuelle Zeit im 'Seriellen Monitor' angezeigt.");
  Serial.println("Ebenso alle Ein- und Ausschaltungen und die Kurzzeittimer-Aktion");
  Serial.println();
  Serial.println("Du kannst die Zeit mit einem 'set' Befehl im 'Serial Monitor' neu setzen.");
  Serial.println("\r\nBeispiel:");
  Serial.println("set 28.08.2013 10:54\r\n");
    
}

void rtcWriteTime(int jahre, int monate, int tage, int stunden, int minuten, int sekunden)
// aktuelle Zeit in der RTC speichern
{
  Wire.beginTransmission(RTC_I2C_ADDRESS);
  Wire.write(0);
  Wire.write(decToBcd(sekunden));    // 0 to bit 7 starts the clock
  Wire.write(decToBcd(minuten));
  Wire.write(decToBcd(stunden));      // If you want 12 hour am/pm you need to set
  // bit 6 (also need to change readDateDs1307)

  Wire.write(decToBcd(0)); // Wochentag unberücksichtigt
  Wire.write(decToBcd(tage));
  Wire.write(decToBcd(monate));
  Wire.write(decToBcd(jahre - 2000));
  Wire.endTransmission();
}

byte decToBcd(byte val) // Hilfsfunktion zum Lesen/Schreiben der RTC
// Convert decimal number to binary coded decimal
// Hilfsfunktion für die Echtzeituhr
{
  return ( (val / 10 * 16) + (val % 10) );
}

byte bcdToDec(byte val)  // Hilfsfunktion zum Lesen/Schreiben der RTC
// Convert binary coded decimal to decimal number
// Hilfsfunktion für die Echtzeituhr
{
  return ( (val / 16 * 10) + (val % 16) );
}


int getIntFromString (char *stringWithInt, byte num)
// input: pointer to a char array
// returns an integer number from the string (positive numbers only!)
// num=1, returns 1st number from the string
// num=2, returns 2nd number from the string, and so on
{
  char *tail;
  while (num > 0)
  {
    num--;
    // skip non-digits
    while ((!isdigit (*stringWithInt)) && (*stringWithInt != 0)) stringWithInt++;
    tail = stringWithInt;
    // find digits
    while ((isdigit(*tail)) && (*tail != 0)) tail++;
    if (num > 0) stringWithInt = tail; // new search string is the string after that number
  }
  return (strtol(stringWithInt, &tail, 10));
}

void behandleSerielleBefehle()
{
  char linebuf[30];
  byte counter;
  if (Serial.available())
  {
    delay(100); // Warte auf das Eintreffen aller Zeichen vom seriellen Monitor
    memset(linebuf, 0, sizeof(linebuf)); // Zeilenpuffer löschen
    counter = 0; // Zähler auf Null
    while (Serial.available())
    {
      linebuf[counter] = Serial.read(); // Zeichen in den Zeilenpuffer einfügen
      if (counter < sizeof(linebuf) - 1) counter++; // Zeichenzähler erhöhen
    }
    // Ab hier ist die Zeile eingelesen
    if (strstr(linebuf, "set") == linebuf) // Prüfe auf Befehl "set" zum Setzen der Zeit
    { // Alle übermittelten Zahlen im String auslesen
      tage = getIntFromString (linebuf, 1);
      monate = getIntFromString (linebuf, 2);
      jahre = getIntFromString (linebuf, 3);
      stunden = getIntFromString (linebuf, 4);
      minuten = getIntFromString (linebuf, 5);
      sekunden = getIntFromString (linebuf, 6);
    }
    else
    {
      Serial.println("Befehl unbekannt.");
      return;
    }
    // Ausgelesene Werte einer groben Plausibilitätsprüfung unterziehen:
    if (jahre < 2000 || monate < 1 || monate > 12 || tage < 1 || tage > 31 || (stunden + minuten) == 0)
    {
      Serial.println(linebuf);
      Serial.println("\r\nFehlerhafte Zeitangabe im 'set' Befehl");
      Serial.println("\r\nBeispiel:");
      Serial.println("set 28.08.2013 10:54\r\n");
      return;
    }
    rtcWriteTime(jahre, monate, tage, stunden, minuten, sekunden);
    Serial.println("Zeit und Datum wurden auf neue Werte gesetzt.");
  }
}
 
//-------------------------------------
void loop() {
  t = rtc.getTime();
  Serial.print(t.hour);
  Serial.print(" Uhr, ");
  Serial.print(t.min);
  Serial.print(" Minuten");
  Serial.println(" ");
  delay (1000);
  sensorState = digitalRead(sensor);   // Sensor wird eingelesen

        if(sensorState == HIGH && t.hour == OnHour && t.min == OnMin){
           Serial.println("REGENSENSOR NASS -> NUR PUMPE AN");
           digitalWrite(pumpe,HIGH);
           }
        else if(sensorState == LOW && t.hour >= OnHour && t.min >= OnMin && t.hour <= 20 && t.min <= 34 ){
                  Serial.println("REGENSENSOR TROCKEN -> PUMPE AN + VENTIL 1 AUF");
                  digitalWrite(pumpe,HIGH);
                  digitalWrite(ventil1,HIGH);
        }
        else if(sensorState == LOW && t.hour >= 20 && t.min >= 35 && t.hour <= 20 && t.min <= 39 ){
                    digitalWrite(ventil1,LOW);
                    digitalWrite(ventil2,HIGH);
                    Serial.println("VENTIL 2 AUF + PUMPE AN");
                }
                else{
                   digitalWrite(ventil1,LOW);
                   digitalWrite(ventil2,LOW);
                   digitalWrite(pumpe,LOW);
                   Serial.println("ALLES AUS UND VENTILE GESCHLOSSEN");
                    }
    

    behandleSerielleBefehle();
   }
   

@HotSystems danke für die Schaltung. Wie setzt du die Auswertung in deinem Programm um? mit analogRead() ?

Ja, genau.
Nur so lässt sich die Schaltschwelle optimal einstellen.