Dieser Beitrag wurde am 09.11.2022 aktualisiert.
Ein Pool im Garten ist was richtig Schönes, manchmal allerdings zu cool zum Reinspringen. Zumindest ging es uns so mit dem Familienpool. Eine Lösung musste her, also begab ich mich ins Neuland, das Internet. Dort fand ich eine schöne Lösung, und zwar Solarmatten von einem bekannten Badezubehör-Hersteller. Gedacht ist, dass die Matten in den Filterkreis gehangen werden. Für mich ist diese Lösung nicht so ideal, da der Pool im Schrebergarten steht und wir dort nicht täglich hingehen. Also stand fest, es muss ein extra Kreislauf mit extra Pumpe sein.
Inhaltsverzeichnis
Aber was brauch ich denn dafür???
Als Nachbauer*in hat man grundsätzlich mehrere Möglichkeiten der Ansteuerung der Pumpe:
– Meine entwickelte Platine verwenden (Extrapunkt weiter unten)
– Eine eigene Platine löten (z.B. mit einer Streifenrasterplatine)
– Eine Solarplatte verwenden (Sonne da -> Solarplatte erzeugt Spannung -> Pumpe läuft)
Je nachdem, für welche man sich entscheidet, braucht man unterschiedliche Elektronikkomponenten.
- Solarmatten: https://www.amazon.de/gp/product/B00MS3963Y/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1
- Wasserpumpe: https://www.amazon.de/gp/product/B0752LF7YX/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1
- Elektronik (mit eigener Platine)
- ESP8266
- 10kOhm Widerstand
- Mosfet (z.B. IRF540N)
- Level-shifter (wenn Logic-Level Mosfet verwendet wird z.B. IRF540N)
- 2x DS18B20 Temperatursensor (Pool- und Rücklauftemperaturmessung)
- 12V 1A Netzteil
- Elektronik (mit meiner Platine)
- ESP12-F
- Elko 2,2 uF (Radial,3x5mm)
- Kerko 100 nF (Through Hole,P=2.54mm)
- 500 Ohm smd Widerstand (SMD 0603)
- 10k Ohm smd Widerstand (SMD 0805)
- Spannungsregler (LF33CV)
- Mosfet (IRF540N)
- 12V 1A Netzteil
- Ausreichend Gartenschlauch
- 1/2 Zoll Schlauchanschlüsse mit Innengewinde
- Adapter von Intex-Schlauch auf Gartenschlauch (hab ich gedruckt, dazu später mehr)
- Rückschlagventil mit Filtersieb
- Edelstahlschellen
Wie wirds verschlaucht?
Wenn man sich an diese Skizze hält, kann nichts schiefgehen.
Worauf man besonders achten sollte:
– Die Pumpe sollte sich immer unter der Wasserlinie befinden, damit sie immer voll mit Wasser ist.
– Es sollte immer ein Rückschlagventil an der Ansaugung verwendet werden, damit das Wasser nicht aus der Heizung durch die Pumpe zurück in den Pool fließt.
Wie wirds verkabelt?
Falls meine Platine verwendet wird, wie auf der nachfolgenden Skizze.
Die beiden Temperatursensoren können einfach parallel geschalten werden durch löten o.Ä.
Das Netzteil sollte mindestens einen Ampere liefern können, um genug Reserven zu bieten.
Immer darauf achten, dass nichts verpolt angeschlossen wird, denn dadurch können Bauteile zerstört werden.
Bei der Wahl der Solarzelle unbedingt darauf achten, dass sie nicht mehr als 1V bei voller Sonneneinstrahlung erzeugt, da der Analog-Digital Wandler vom ESP nur 1V verträgt. Meine Solarzelle erzeugt bei voller Einstrahlung 6V. Ich habe sie dann soweit mit Klebeband abgeklebt, bis sie nur noch 1V erzeugt hat.
Wie funktioniert die Regelung?
Der Mikrocontroller sorgt dafür, dass die Pumpe nur pumpt wenn es sich auch lohnt. Damit das zuverlässig funktioniert, verfügt er über 3 verschiedene Sensoren. Durch ein Solarpanel erkennt der Mikrocontroller, ob und wie stark die Sonne scheint. Kommt also eine Wolke vor die Sonne, wird dies erkannt und der Mikrocontroller reagiert gegebenenfalls darauf. Die Reaktion hängt von dem Temperaturunterschied zwischen Pool- und Rücklauftemperatur ab. Ist die Rücklauftemperatur kaum oder gar nicht über der Pooltemperatur und das Solarpanel erkennt eine Wolke, wird die Pumpe abgeschaltet. Wenn das Solarpanel erkennt, dass die Wolke weg ist, wird die Pumpe wieder eingeschaltet. Genauso verhält es sich, wenn es dunkel wird. Durch diese Regelung wird gewährleistet, dass immer die maximal mögliche Heizleistung erziehlt wird.
Gesteuert wird das Ganze über eine Webpage, die unter der IP-Adresse 192.168.4.1 innerhalb des Wlan-Netzwerks des ESP zu erreichen ist.
Auf der Hauptseite sind alle relevanten Informationen zu sehen und es kann die Solltemperatur korrigiert sowie die Steuerung abgeschaltet werden.
Außer der Hauptseite gibt es noch eine „Admin“ Seite, auf der noch mehr Informationen angezeigt werden können. Auf der Admin-Seite kann man auch die Schwellwerte für die Tag/Nacht-Regelung ändern und die Pumpe direkt ein- und ausschalten.
Wie bekomme ich die Platinen?
Die Platinen habe ich bei einem großen Platinenhersteller aus Fernost bestellt. Das kann jeder sehr günstig machen und so meine Platine für dieses Projekt verwenden. Weiter unten stelle ich die Gerber-Dateien für die Platine zum Download zur Verfügung. Den Zip-Ordner einfach bei dem Platinenhersteller der Wahl hochladen und die Platinen bestellen.
Der Programmcode
Der Code ist noch in Arbeit und teilweise nicht kommentiert.
Es wurden folgende Libraries verwendet:
– ESP8266WiFi (Version 1.0)
– WifiClient (Version 1.1)
– ESP8266Webserver
– OneWire (Version 2.3.4 )
– DallasTemperature ( 3.8.0 )
#include <ESP8266WiFi.h> #include <WiFiClient.h> #include <ESP8266WebServer.h> #include <OneWire.h> #include <DallasTemperature.h> #ifndef APSSID #define APSSID "POOL_AP" // Das kann nach belieben geändert werden #define APPSK "yourpassword" // Das kann auch nach belieben geändert werden #endif #define ONE_WIRE_BUS 12 // An welchem GPIO die Temperatursensoren angeschlossen sind #define Temperatursensor_1 0 // diesen Wert auf 1 ändern, wenn die Temperatursensoren vertauscht angezeigt werden #define Temperatursensor_2 1 // diesen Wert auf 0 ändern, wenn die Temperatursensoren vertauscht angezeigt werden const char *ssid = APSSID; const char *password = APPSK; WiFiServer server(80); String header; // Current time unsigned long currentTime = millis(); // Previous time unsigned long previousTime = 0; // Define timeout time in milliseconds (example: 2000ms = 2s) const long timeoutTime = 2000; OneWire oneWire(ONE_WIRE_BUS); DallasTemperature sensors(&oneWire); // Variablen für CTRL() boolean onoff; //Steuerung ist an/aus true = an / false = aus boolean merker_onoff; //Merker für Toggleroutine boolean tagnacht; //true = Tag- / false = Nachtmodus boolean merker_tagnacht; //Merker für Toggleroutine boolean Wolke; //true = Wolke erkannt / false = keine Wolke erkannt boolean zyklus; //n.V. boolean admin; //true = adminmodus ist aktiv / false = adminmodus ist inaktiv boolean pumpe; //true = Pumpe wird eingeschaltet / false = Pumpe wird ausgeschaltet int Schwellwert_EIN = 100; //Der Schwellwert, bei dem der Tagmodus aktiviert wird int Schwellwert_AUS = 50; //Der Schwellwert, bei dem der Tagmodus deaktiviert wird int value_Wolke; //Der Wert, bei dem die Steuerung "Wolke" false setzen soll float wassertemp; //Die momentane Wassertemperatur float Ruecklauftemp; //Die momentane Rücklauftemperatur float Solltemp = 23.0; //Die momentane Solltemperatur // Merkervariablen für die Timer unsigned long Nachtstamp; unsigned long Tagstamp; unsigned long Wolke_weg; unsigned long Wolke_da; unsigned long tagnacht_millistamp; unsigned long millistamp; // Variablen für statistic() int Power; int Power_Tag; int Power_Vortag; int Tage_seit_boot; int Power_seit_boot; // Variablen für watchdog() boolean alarm_admin; boolean alarm_wolke; boolean alarm_tagnacht; unsigned long watchdog_admin; unsigned long watchdog_wolke; unsigned long watchdog_tagnacht; // Allgemeine Variablen int pumppin = 4; const int analogpin = A0; int value; //*********************************************SETUP**************************************************************** void setup(){ delay(1000); millistamp = millis(); pinMode(pumppin, OUTPUT); Wolke = false; value_Wolke = 100; Serial.begin(115200); admin = false; sensors.begin(); delay(1000); Serial.print("Accesspoint wird konfiguriert..."); WiFi.mode(WIFI_AP); WiFi.softAP(ssid, password); IPAddress myIP = WiFi.softAPIP(); Serial.print("AP IP address: "); Serial.println(myIP); server.begin(); Serial.println("HTTP server started"); Serial.print("AP IP address: "); Serial.println(myIP); // server.on("/action_page", FORMS); delay(1000); tagnacht = true; merker_tagnacht = true; Wolke = false; Wolke_weg = millis() + 600000; // 10min } //*********************************************LOOP**************************************************************** void loop(){ WIFI(); if(millistamp <= millis()){ millistamp = millis(); millistamp = millistamp + 3000; value = analogRead(analogpin); Serial.print("ADC: "); Serial.print(value); Serial.print("\n"); TEMP(); } CTRL(); statistic(); Watchdog(); } //*********************************************TEMP**************************************************************** void TEMP(){ sensors.requestTemperatures(); Ruecklauftemp = sensors.getTempCByIndex(Temperatursensor_1); wassertemp = sensors.getTempCByIndex(Temperatursensor_2); Serial.print("Wassertemperatur: "); Serial.print(wassertemp); Serial.print("\n"); Serial.print("Ruecklauftemperatur: "); Serial.print(Ruecklauftemp); Serial.print("\n"); if(tagnacht)Serial.println("TAG"); if(!tagnacht)Serial.println("NACHT"); if(pumpe)Serial.println("Pumpe läuft"); if(!pumpe)Serial.println("Pumpe läuft nicht"); } //*********************************************WIFI**************************************************************** void WIFI(){ WiFiClient client = server.available(); // Listen for incoming clients if (client) { // If a new client connects, Serial.println("New Client."); // print a message out in the serial port String currentLine = ""; // make a String to hold incoming data from the client currentTime = millis(); previousTime = currentTime; while (client.connected() && currentTime - previousTime <= timeoutTime) { // loop while the client's connected currentTime = millis(); if (client.available()) { // if there's bytes to read from the client, char c = client.read(); // read a byte, then Serial.write(c); // print it out the serial monitor header += c; if (c == '\n') { // if the byte is a newline character // if the current line is blank, you got two newline characters in a row. // that's the end of the client HTTP request, so send a response: if (currentLine.length() == 0) { // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK) // and a content-type so the client knows what's coming, then a blank line: client.println("HTTP/1.1 200 OK"); client.println("Content-type:text/html"); client.println("Connection: close"); client.println(); if (header.indexOf("GET /pooltemp/plus") >= 0) { Serial.println("Temp + 1"); Solltemp = Solltemp + 1.0; } if (header.indexOf("GET /pooltemp/minus") >= 0) { Serial.println("Temp - 1"); Solltemp = Solltemp - 1.0; } if (header.indexOf("GET /pooltemp/off") >= 0) { Serial.println("abgeschaltet"); onoff = !onoff; } if (header.indexOf("GET /pooltemp/on") >= 0) { Serial.println("angeschaltet"); onoff = !onoff; } if (header.indexOf("GET /admin/on") >= 0) { Serial.println("Admin"); admin = true; watchdog_admin = millis() + 3600000; // 1 Stunde } if (header.indexOf("GET /admin/off") >= 0) { Serial.println("Admin"); admin = false; } if (header.indexOf("GET /admin/pumpon") >= 0) { Serial.println("Admin"); pumpe = true; } if (header.indexOf("GET /admin/pumpoff") >= 0) { Serial.println("Admin"); pumpe = false; } if (header.indexOf("GET /admin/tag") >= 0) { Serial.println("Admin"); tagnacht = true; } if (header.indexOf("GET /admin/nacht") >= 0) { Serial.println("Admin"); tagnacht = false; } if (header.indexOf("GET /admin/adcplus") >= 0) { Serial.println("Admin"); Schwellwert_EIN = Schwellwert_EIN + 10; } if (header.indexOf("GET /admin/adcminus") >= 0) { Serial.println("Admin"); Schwellwert_EIN = Schwellwert_EIN - 10; } client.println("<!DOCTYPE html><html>"); client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">"); client.println("<link rel=\"icon\" href=\"data:,\">"); // CSS to style the on/off buttons // Feel free to change the background-color and font-size attributes to fit your preferences client.println("<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}"); client.println(".button { background-color: #0075b0; border: none; color: white; padding: 16px 40px;"); client.println("text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer; float: left;}"); client.println(".button2 {background-color: #0075b0;}</style></head>"); // Web Page Heading client.println("<body><h1>Poolmanagement</h1>"); if(admin){ client.println("<p>ADC IST: "); client.println(value); client.println("</p>"); client.println("<p>ADC Einschalt Schwellwert: "); client.println(Schwellwert_EIN); client.println("</p>"); client.println("<p>ADC Ausschalt Schwellwert: "); client.println(Schwellwert_AUS); client.println("</p>"); client.println("<p>Tage seit BOOT: "); client.println(Tage_seit_boot); client.println("</p>"); } client.println("<p>Wassertemperatur: "); client.println(wassertemp); client.println("</p>"); client.println("<p>Ruecklauftemperatur: "); client.println(Ruecklauftemp); client.println("</p>"); client.println("<p>Aktuelle Heizleistung in WATT: "); client.println(Power); client.println("</p>"); if(Wolke){client.println("<p>Wolke da "); client.println("</p>"); } if(!Wolke){client.println("<p>keine Wolke da "); client.println("</p>"); } client.println("<p>Solltemperatur: "); client.println(Solltemp); client.println("</p>"); client.println("<table>"); client.println("<tr>"); client.println("<th>"); client.println("<p><a href=\"/\"><button class=\"button\">Refresh</button></a></p>"); client.println("</th>"); client.println("<th>"); client.println("<p>"); client.println("Aktualisieren"); client.println("</p>"); client.println("</th>"); client.println("</tr>"); client.println("<tr>"); client.println("<th>"); client.println("<p><a href=\"/pooltemp/plus\"><button class=\"button\">+</button></a></p>"); client.println("</th>"); client.println("<th>"); client.println("<p>"); client.println("Solltemp + 1C"); client.println("</p>"); client.println("</th>"); client.println("</tr>"); client.println("<tr>"); client.println("<th>"); client.println("<p><a href=\"/pooltemp/minus\"><button class=\"button\">-</button></a></p>"); client.println("</th>"); client.println("<th>"); client.println("<p>"); client.println("Solltemp - 1C"); client.println("</p>"); client.println("</th>"); client.println("</tr>"); client.println("<tr>"); client.println("<th>"); if(onoff)client.println("<p><a href=\"/pooltemp/off\"><button class=\"button\">OFF</button></a></p>"); if(!onoff)client.println("<p><a href=\"/pooltemp/on\"><button class=\"button\">ON</button></a></p>"); client.println("</th>"); client.println("<th>"); client.println("<p>"); if(onoff)client.println("Steuerung Abschalten"); if(!onoff)client.println("Steuerung Einschalten"); client.println("</p>"); client.println("</th>"); client.println("</tr>"); if(admin){ client.println("<tr>"); client.println("<th>"); client.println("<p><a href=\"/admin/tag\"><button class=\"button\">Tagmodus</button></a></p>"); client.println("</th>"); client.println("<th>"); client.println("<p>"); client.println("Tagmodus aktivieren"); client.println("</p>"); client.println("</th>"); client.println("</tr>"); client.println("<tr>"); client.println("<th>"); client.println("<p><a href=\"/admin/nacht\"><button class=\"button\">Nachtmodus</button></a></p>"); client.println("</th>"); client.println("<th>"); client.println("<p>"); client.println("Nachtmodus aktivieren"); client.println("</p>"); client.println("</th>"); client.println("</tr>"); client.println("<tr>"); client.println("<th>"); if(pumpe)client.println("<p><a href=\"/admin/pumpoff\"><button class=\"button\">OFF</button></a></p>"); if(!pumpe)client.println("<p><a href=\"/admin/pumpon\"><button class=\"button\">ON</button></a></p>"); client.println("</th>"); client.println("<th>"); client.println("<p>"); if(pumpe)client.println("Pumpe Abschalten"); if(!pumpe)client.println("Pumpe Einschalten"); client.println("</p>"); client.println("</th>"); client.println("</tr>"); client.println("<tr>"); client.println("<th>"); client.println("<p><a href=\"/admin/adcplus\"><button class=\"button\">+</button></a></p>"); client.println("</th>"); client.println("<th>"); client.println("<p>"); client.println("Schwellwert + 10"); client.println("</p>"); client.println("</th>"); client.println("</tr>"); client.println("<tr>"); client.println("<th>"); client.println("<p><a href=\"/admin/adcminus\"><button class=\"button\">-</button></a></p>"); client.println("</th>"); client.println("<th>"); client.println("<p>"); client.println("Schwellwert - 10"); client.println("</p>"); client.println("</th>"); client.println("</tr>"); client.println("<tr>"); client.println("<th>"); client.println("<p><a href=\"/admin/off\"><button class=\"button\">OFF</button></a></p>"); client.println("</th>"); client.println("<th>"); client.println("<p>"); client.println("Adminmodus ausschalten"); client.println("</p>"); client.println("</th>"); client.println("</tr>"); } client.println("</table>"); client.println("</body></html>"); // The HTTP response ends with another blank line client.println(); // Break out of the while loop break; } else { // if you got a newline, then clear currentLine currentLine = ""; } } else if (c != '\r') { // if you got anything else but a carriage return character, currentLine += c; // add it to the end of the currentLine } } } // Clear the header variable header = ""; // Close the connection client.stop(); Serial.println("Client disconnected."); Serial.println(""); } } //*********************************************CTRL**************************************************************** void CTRL(){ if(value <= Schwellwert_EIN && tagnacht == false){ tagnacht_millistamp = millis(); tagnacht_millistamp = tagnacht_millistamp + 6000000; // 100min } if(value > Schwellwert_AUS && tagnacht == true){ tagnacht_millistamp = millis(); tagnacht_millistamp = tagnacht_millistamp + 6000000; // 100min } if(tagnacht_millistamp <= millis() && tagnacht == true){ tagnacht = false; } if(tagnacht_millistamp <= millis() && tagnacht == false){ tagnacht = true; } if(Power <= 300 && pumpe == true && Wolke == false && value < 600 && tagnacht == true){ Wolke = true; if(value < 800)value_Wolke = value + 200; if(value >= 800)value_Wolke = 1024; } if(Wolke == true && value >= value_Wolke && Wolke_weg < millis() && tagnacht == true){ Wolke = false; Wolke_weg = millis() + 600000; // 10min } if(admin == false){ if(tagnacht == true && wassertemp <= Solltemp && onoff == true && Wolke == false)pumpe = true; if(wassertemp > Solltemp || onoff == false || tagnacht == false || Wolke == true)pumpe = false; OUT(); } } //*********************************************OUT**************************************************************** void OUT(){ if(pumpe == true)digitalWrite(pumppin, HIGH); if(pumpe == false)digitalWrite(pumppin, LOW); } //*********************************************statistic**************************************************************** void statistic(){ if(pumpe == true){ Power = Ruecklauftemp - wassertemp; Power = Power * 4176; Power = Power / 16; } if(pumpe == false)Power = 0; if(tagnacht == true && merker_tagnacht == false){ Tage_seit_boot = Tage_seit_boot + 1; merker_tagnacht = true; } if(tagnacht == false && merker_tagnacht == true){ merker_tagnacht = false; Wolke = false; value_Wolke = 0; } } //*********************************************Watchdog**************************************************************** void Watchdog(){ if(watchdog_admin <= millis()){ alarm_admin = true; admin = false; } // if(watchdog_wolke <= millis()){ // alarm_wolke = true; // wolke = false; // } }