====== Bewässerungsautomat Programmversion 0.3 ====== Diese Programmversion wird nicht mehr weiter entwickelt. Weiter geht es mit [[programmversion_0.4|Programmversion 0.4]] Gegenüber [[Programmversion 0.2 alpha]] wurde verändert: * Der DHT22 wird ausgelesen und die Werte an die serielle Schnittstelle ausgegeben. * Auf Basis der gemessenen Temperatur und Luftfeuchte wird der Hitzeindex berechnet und an die serielle Schnittstelle ausgegeben. * Auf Basis der gemessenen Temperatur und Luftfeuchte wird der Taupunk berechnet und an die serielle Schnittstelle ausgegeben. * Wenn die Gehäuseinnentemperatur unter den Taupunkt fällt, leuchten am NeoPixel-Ring am Wasserstandssensor zwei LEDs rot statt weiß. * Der Wasserstandssensor für den Vorratsbehälter wird ausgelesen und in einen prozentualen Füllstand umgerechnet. Damit funktioniert jetzt auch die Ansteuerung des NeoPixel-Rings am Wasserstandssensor. * Der TSL2591 wird ausgelesen und die Werte an die serielle Schnittstelle ausgegeben. * Auf Basis der gemessenen Helligkeit wird eine Variable berechnet, mit der die Helligkeit der NeoPixel gesteuert wird. Hilfreiche Links: * http://fluuux.de/2012/10/arduino-temperatur-und-luftfeuchtigkeit-mit-dem-dht22-prufen/ * https://learn.adafruit.com/thermistor (Ich will zwar keinen Thremistor anschließen, aber der Level-Sensor funktioniert genauso.)) * https://learn.adafruit.com/adafruit-tsl2591/overview * https://forums.adafruit.com/viewtopic.php?f=47&t=41143 (Sehr hilfreich für die automatische Anpassung der Helligkeit der NeoPixels.) * https://learn.adafruit.com/introducing-bluefruit-ez-link Was noch zu tun ist (in dieser oder einer späteren Programmversion): * Damit die Neopixel blinken oder pulsieren können, müsste das Programm ohne den delay-Befehl auskommen. * Wenn das Programm entsprechend umgestellt wurde, sollen die NeiPixel in den Blumenkastensensoren pulsieren. * Für die NeoPixel-Ringe sind Animationen denkbar. * Bluetooth * Der Wasserstandssensor könnte schneller ausgelesen und ein Mittelwert über die letzten X Messwerte gebildet werden, um schnelle Schwankungen, die auf Messfehler zurückgehen, zu vermeiden. * Es wäre zu überlegen, wie der gemessene Referenzwiederstand in die Berechnung des Wasserstands einbezogen werden kann. ===== Belegung der Arduino-Pins für diese Programmversion ===== Im Folgenden ist die Pin-Belegung am Arduino **für diese Programmversion** dokumentiert. Um Verwechselungen vorzubeugen, ist außerdem die Farbe der Kabel der Signalleitungen dokumentiert. Strom: * GND: Masse von Stromverteilerplatine * Vin: 5 Volt von Stromverteilerplatine Müssen vom Proto-Board mit Strom versorgt werden: * NeoPixel-Ring 1 * BeoPixel-Ring 2 * TSL2591 Analoge Eingänge * A0: Variabler Widerstand Level-Sensor und über 1500 Ohm-Widerstand an 5 Volt * A1: Konstanter Widerstand Level-Sensor und über 1500 Ohm-Widerstand an 5 Volt Digitale Eingänge: * Pin 26: Hall-Schalter 1 (direkt) (blau) * Pin 28: Hall-Schalter 2 (direkt) (blau) * Pin 30: Hall-Schalter 3 (direkt) (blau) * Pin 32: Hall-Schalter 4 (direkt) (blau) * Pin 46: Masse Blumenkastensensor 1 (direkt) (grün) * Pin 48: Masse Blumenkastensensor 2 (direkt) (grün) * Pin 50: Masse Blumenkastensensor 3 (direkt) (grün) * Pin 52: Masse Blumenkastensensor 4 (direkt) (grün) * Pin 39: DHT22 (grün) Digitale Ausgänge: * Pin 36: Relais 1 (direkt) (gelb) * Pin 38: Realis 2 (direkt) (grün) * Pin 40: Relais 3 (direkt) (gelb) * Pin 42: Relais 4 (direkt) (grün) NeoPixel: * Pin 12: Blumenkastensensor 1 über 470 Ohm (gelb) * Pin 11: Blumenkastensensor 2 über 470 Ohm (gelb) * Pin 10: Blumenkastensensor 3 über 470 Ohm (gelb) * Pin 9: Blumenkastensensor 4 über 470 Ohm (gelb) * Pin 8: Wasserstandssensor über 470 Ohm (gelb) * Pin 7: Neopixelring 1 über 470 Ohm (gelb) * Pin 6: Neopixelring 2 über 470 Ohm (gelb) I2C-Bus: * SDA (20): TSL2591 (gelb) * SCL (21): TSL2591 (blau) ===== Code ===== // Bibliotheken einbinden #include #include #include #include "Adafruit_TSL2591.h" #include "DHT.h" // Definiert die Pins für die NeoPixels int neoPin1 = 12; // Neopixel an Blumenkastenensor 1 int neoPin2 = 11; // Neopixel an Blumenkastenensor 2 int neoPin3 = 10; // Neopixel an Blumenkastenensor 3 int neoPin4 = 9; // Neopixel an Blumenkastenensor 4 int neoPin5 = 8; // Neopixelring am Wasserstandssensor im Vorratsbehälter int neoPin6 = 7; // Neopixelring im Gehäusedeckel //int neoPin6 = 6; // Reserviert für Erweiterungen //int neoPin6 = 5; // Reserviert für Erweiterungen // Definiert die NeoPixels Adafruit_NeoPixel neopix1 = Adafruit_NeoPixel(1, neoPin1, NEO_GRB + NEO_KHZ800); Adafruit_NeoPixel neopix2 = Adafruit_NeoPixel(1, neoPin2, NEO_GRB + NEO_KHZ800); Adafruit_NeoPixel neopix3 = Adafruit_NeoPixel(1, neoPin3, NEO_GRB + NEO_KHZ800); Adafruit_NeoPixel neopix4 = Adafruit_NeoPixel(1, neoPin4, NEO_GRB + NEO_KHZ800); Adafruit_NeoPixel neopix5 = Adafruit_NeoPixel(12, neoPin5, NEO_RGBW + NEO_KHZ800); Adafruit_NeoPixel neopix6 = Adafruit_NeoPixel(24, neoPin6, NEO_RGBW + NEO_KHZ800); // pass in a number for the sensor identifier (for your use later) Adafruit_TSL2591 tsl = Adafruit_TSL2591(2591); // Definiert die Pins für die Hall-Sensoren int hallPin1 = 32; // Hall-Sensor 1 int hallPin2 = 30; // Hall-Sensor 2 int hallPin3 = 28; // Hall-Sensor 3 int hallPin4 = 26; // Hall-Sensor 4 // Definiert die Pins für die Verfügbarkeitskontrolle int massePin1 = 46; // Masse an Blumenkastenensor 1 int massePin2 = 48; // Masse an Blumenkastenensor 2 int massePin3 = 50; // Masse an Blumenkastenensor 3 int massePin4 = 52; // Masse an Blumenkastenensor 4 // Definiert die Pins des Wasserstandssensor für den Vorratsbehälter int refPin = A1; // Rref int levelPin = A2; // Rsense // Definiert den Pin für den DHT22 int dhtPin = 39; // Definiert den angeschlossenen Sensor #define DHTTYPE DHT22 // DHT 22 (AM2302), AM2321) // Initialisiert den DHT-Sensor DHT dht(dhtPin, DHTTYPE); // Definiert die Pins für die Pumpenrelais int relPin1 = 36; // Pumpe 1 int relPin2 = 38; // Pumpe 2 int relPin3 = 40; // Pumpe 3 int relPin4 = 42; // Pumpe 4 // Definiert die Variablen int hall1 = LOW; int hall2 = LOW; int hall3 = LOW; int hall4 = LOW; int masse1 = LOW; int masse2 = LOW; int masse3 = LOW; int masse4 = LOW; int rlevel = 0; int rref = 0; int brightness = 0; void setup() { // Initialisiere die NeoPixel-Pins pinMode(neoPin1, OUTPUT); pinMode(neoPin2, OUTPUT); pinMode(neoPin3, OUTPUT); pinMode(neoPin4, OUTPUT); pinMode(neoPin5, OUTPUT); pinMode(neoPin6, OUTPUT); // Initialisiere die Hall-Pins als Inputs mit Pullup. Außerdem werden die internen Pullup-Widerstände aktiviert. // Liegt an dem Hall-Sensor ein Magnetfeld an, ist der Input LOW, ansonsten ist der Input HIGH. pinMode(hallPin1, INPUT_PULLUP); pinMode(hallPin2, INPUT_PULLUP); pinMode(hallPin3, INPUT_PULLUP); pinMode(hallPin4, INPUT_PULLUP); pinMode(massePin1, INPUT_PULLUP); pinMode(massePin2, INPUT_PULLUP); pinMode(massePin3, INPUT_PULLUP); pinMode(massePin4, INPUT_PULLUP); //Initialisiert den Pin für den DHT22 als Input mit Pullup pinMode(dhtPin, INPUT_PULLUP); // Initialisiere die Relais-Pins pinMode(relPin1, OUTPUT); pinMode(relPin2, OUTPUT); pinMode(relPin3, OUTPUT); pinMode(relPin4, OUTPUT); // Initialisiere den Wasserstandssensor pinMode(rlevel, INPUT); pinMode(rref, INPUT); // Initialisiere alle NeoPixels neopix1.begin(); neopix1.show(); // Initialize all pixels to 'off' neopix2.begin(); neopix2.show(); // Initialize all pixels to 'off' neopix3.begin(); neopix3.show(); // Initialize all pixels to 'off' neopix4.begin(); neopix4.show(); // Initialize all pixels to 'off' neopix5.begin(); neopix5.show(); // Initialize all pixels to 'off' neopix6.begin(); neopix6.show(); // Initialize all pixels to 'off' // Konfiguration des TSL2591 // You can change the gain on the fly, to adapt to brighter/dimmer light situations //tsl.setGain(TSL2591_GAIN_LOW); // 1x gain (bright light) tsl.setGain(TSL2591_GAIN_MED); // 25x gain // tsl.setGain(TSL2591_GAIN_HIGH); // 428x gain // Changing the integration time gives you a longer time over which to sense light // longer timelines are slower, but are good in very low light situtations! tsl.setTiming(TSL2591_INTEGRATIONTIME_100MS); // shortest integration time (bright light) // tsl.setTiming(TSL2591_INTEGRATIONTIME_200MS); // tsl.setTiming(TSL2591_INTEGRATIONTIME_300MS); // tsl.setTiming(TSL2591_INTEGRATIONTIME_400MS); // tsl.setTiming(TSL2591_INTEGRATIONTIME_500MS); // tsl.setTiming(TSL2591_INTEGRATIONTIME_600MS); // longest integration time (dim light) // Debugging output Serial.begin(9600); dht.begin(); tsl.begin(); delay(2000); // Diese Pause benötigt der DHT22 um erste Messwerte zu lesen. // Perspektivisch könnte eine Startanimation des NeoPixel-Rings die Wartezeit verkürzen. } void loop() { // Auslesen der digitalen Eingänge hall1 = digitalRead(hallPin1); hall2 = digitalRead(hallPin2); hall3 = digitalRead(hallPin3); hall4 = digitalRead(hallPin4); masse1 = digitalRead(massePin1); masse2 = digitalRead(massePin2); masse3 = digitalRead(massePin3); masse4 = digitalRead(massePin4); // Auslesen der analogen Eingänge rlevel = analogRead(levelPin); rref = analogRead(refPin); // Ausgabe der Eingangssignale an den digitalen Masse-Pins an die serielle Schnittstelle // Der Ausgabewert "0" bedeutet, dass der entsprechende Blumenkastensensor angeschlossen ist Serial.print("Sensor Kasten 1: "); Serial.print(masse1); Serial.print(" \t"); Serial.print("Sensor Kasten 2: "); Serial.print(masse2); Serial.print(" \t"); Serial.print("Sensor Kasten 3: "); Serial.print(masse3); Serial.print(" \t"); Serial.print("Sensor Kasten 4: "); Serial.print(masse4); Serial.println(" \t"); // Ausgabe der Eingangssignale an den digitalen Hall-Pins an die serielle Schnittstelle // Der Ausgabewert "1" bedeutet, dass kein Magnetfeld gemessen wird Serial.print("Hallschalter 1: "); Serial.print(hall1); Serial.print(" \t"); Serial.print("Hallschalter 2: "); Serial.print(hall2); Serial.print(" \t"); Serial.print("Hallschalter 3: "); Serial.print(hall3); Serial.print(" \t"); Serial.print("Hallschalter 4: "); Serial.print(hall4); Serial.println(" \t"); // Ausgabe des Eingangssignals an den analogen Wasserstands-Pins an die serielle Schnittstelle Serial.print("Wert Sensorwiderstand: "); Serial.print(rlevel); Serial.print("\t"); Serial.print("Wert Referenzwiederstand: "); Serial.print(rref); Serial.println("\t"); // Berechnung des Wasserstands im Vorratsbehälter in Prozent float rlevelmin = 830; // Messwert bei minimalem Wasserstand float rlevelmax = 430; // Messwert bei maximalem Wasserstand float level = 100 - (((rlevelmax - rlevel) / (rlevelmax - rlevelmin)) * 100); // Ausgabe des Wasserstands im Vorratsbehälter in Prozent an die serielle Schnittstelle Serial.print("Wasserstand: "); Serial.print(level); Serial.println(" %"); // More advanced data read example. Read 32 bits with top 16 bits IR, bottom 16 bits full spectrum // That way you can do whatever math and comparisons you want! uint32_t lum = tsl.getFullLuminosity(); uint16_t ir, full; ir = lum >> 16; full = lum & 0xFFFF; Serial.print("[ "); Serial.print(millis()); Serial.print(" ms ] "); Serial.print("IR: "); Serial.print(ir); Serial.print(" "); Serial.print("Full: "); Serial.print(full); Serial.print(" "); Serial.print("Visible: "); Serial.print(full - ir); Serial.print(" "); Serial.print("Lux: "); Serial.println(tsl.calculateLux(full, ir)); // Berechnung der Helligkeit der NeoPixel float brightness = log(full) / 10; Serial.print(brightness); // Ansteuerung der Pumpen. // Ist der Wasserstand niedrig, liegt kein Magnetfeld am Hall-Sensor an (hall = 1). // Die entsprechende Pumpe wird aktiviert, bis der Soll-Wasserstand erreicht ist (hall = 0), // - sofern keine andere Pumpe läuft und // - sofern Wasser im Vorratsbehälter ist. // Pumpe 1 if (masse1 == 0 && hall1 == 1 && level > 5 && digitalRead(relPin2) == HIGH && digitalRead(relPin3) == HIGH && digitalRead(relPin4) == HIGH) { digitalWrite(relPin1, LOW); } else { digitalWrite(relPin1, HIGH); } // Pumpe 2 if (masse2 == 0 && hall2 == 1 && level > 5 && digitalRead(relPin1) == HIGH && digitalRead(relPin3) == HIGH && digitalRead(relPin4) == HIGH) { digitalWrite(relPin2, LOW); } else { digitalWrite(relPin2, HIGH); } // Pumpe 3 if (masse3 == 0 && hall3 == 1 && level > 5 && digitalRead(relPin1) == HIGH && digitalRead(relPin2) == HIGH && digitalRead(relPin4) == HIGH) { digitalWrite(relPin3, LOW); } else { digitalWrite(relPin3, HIGH); } // Pumpe 4 if (masse4 == 0 && hall4 == 1 && level > 5 && digitalRead(relPin1) == HIGH && digitalRead(relPin2) == HIGH && digitalRead(relPin3) == HIGH) { digitalWrite(relPin4, LOW); } else { digitalWrite(relPin4, HIGH); } // Ansteuerung der NeoPixels in den Blumenkastensensoren if (hall1 == 0) { neopix1.setPixelColor(0, 0, 255*brightness, 0); //grün-weiß, wenn Wasserstand ok } else { neopix1.setPixelColor(0, 255*brightness, 0, 0); //rot, wenn Wasserstand niedrig } neopix1.show(); if (hall2 == 0) { neopix2.setPixelColor(0, 0, 255*brightness, 0); //grün-weiß, wenn Wasserstand ok } else { neopix2.setPixelColor(0, 255*brightness, 0, 0); //rot, wenn Wasserstand niedrig } neopix1.show(); if (hall3 == 0) { neopix3.setPixelColor(0, 0, 255*brightness, 0); //grün-weiß, wenn Wasserstand ok } else { neopix3.setPixelColor(0, 255*brightness, 0, 0); //rot, wenn Wasserstand niedrig } neopix3.show(); if (hall4 == 0) { neopix4.setPixelColor(0, 0, 255*brightness, 0); //grün-weiß, wenn Wasserstand ok } else { neopix4.setPixelColor(0, 255*brightness, 0, 0); //rot, wenn Wasserstand niedrig } neopix4.show(); //Ansteuerung des NeoPixel-Rings im Wasserstandssensor für den Vorratsbehälter neopix5.setPixelColor(0, 0, 0, 0, 127); neopix5.setPixelColor(11, 0, 0, 0, 127); if (level >= 90) { neopix5.setPixelColor(10, 0, 255*brightness, 0, 0); } else if (level < 90) { neopix5.setPixelColor(10, 0, 0, 0, 0); } if (level >= 80) { neopix5.setPixelColor(9, 0, 255*brightness, 0, 0); } else if (level < 80) { neopix5.setPixelColor(9, 0, 0, 0, 0); } if (level >= 70) { neopix5.setPixelColor(8, 0, 255*brightness, 0, 0); } else if (level < 70) { neopix5.setPixelColor(8, 0, 0, 0, 0); } if (level >= 60) { neopix5.setPixelColor(7, 0, 255*brightness, 0, 0); } else if (level < 60) { neopix5.setPixelColor(7, 0, 0, 0, 0); } if (level >= 50) { neopix5.setPixelColor(6, 127*brightness, 127*brightness, 0, 0); } else if (level < 50) { neopix5.setPixelColor(6, 0, 0, 0, 0); } if (level >= 40) { neopix5.setPixelColor(5, 127*brightness, 127*brightness, 0, 0); } else if (level < 40) { neopix5.setPixelColor(5, 0, 0, 0, 0); } if (level >= 30) { neopix5.setPixelColor(4, 127*brightness, 127*brightness, 0, 0); } else if (level < 30) { neopix5.setPixelColor(4, 0, 0, 0, 0); } if (level >= 20) { neopix5.setPixelColor(3, 255*brightness, 0, 0, 0); } else if (level < 20) { neopix5.setPixelColor(3, 0, 0, 0, 0); } if (level >= 10) { neopix5.setPixelColor(2, 255*brightness, 0, 0, 0); } else if (level <10) { neopix5.setPixelColor(2, 0, 0, 0, 0); } neopix5.show(); // Auslesen des DHT22 und Ausgabe der Werte an serielle Schnittstelle // Reading temperature or humidity takes about 250 milliseconds! // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor) float h = dht.readHumidity(); // Luftfeuchte auslesen float t = dht.readTemperature(); //Temperatur in Grad Celsius auslesen // Check if any reads failed and exit early (to try again). if (isnan(h) || isnan(t)) { Serial.println("DHT22 konnte nicht ausgelesen werden!"); return; } // Hitzeindex in Celsius berechnen (isFahreheit = false) float hic = dht.computeHeatIndex(t, h, false); // Taupunkt berechnen float a = 17.271; float b = 237.7; float taupunktTmp = (a * t) / (b + t) + log(h/100); float taupunkt = (b * taupunktTmp) / (a - taupunktTmp); Serial.print("Luftfeuchte: "); Serial.print(h); Serial.print(" %\t"); Serial.print("Temperatur: "); Serial.print(t); Serial.print(" *C\t"); Serial.print("Hitzeindex: "); Serial.print(hic); Serial.print(" *C\t"); Serial.print("Taupunkt: "); Serial.print(taupunkt); Serial.println(" *C"); // Warnung bei Unterschreiten der Gehäuseinnentemperatur unter den Taupunkt if (t <= taupunkt) { neopix5.setPixelColor(0, 127, 0, 0, 0); neopix5.setPixelColor(11, 127, 0, 0, 0); } else if (t > taupunkt) { neopix5.setPixelColor(0, 0, 0, 0, 127); neopix5.setPixelColor(11, 0, 0, 0, 127); } delay(1000); // 1 Sek Pause } Tags: #Arduino #Bewässerungsautomat #Code