Da ich vom meinem Heizungskeller einen Schlauch quer durch meinen Wäschekeller für den Ablauf des Kondensats aus dem Kamin liegen hatte, suchte ich eine für mich optimale Lösung um das kontaminierte Wasser abzupumpen.
Die angebotenen Lösungen waren in meinen Augen zu kostenintensiv, weswegen ich mich hinsetzte und eine eigene Lösung entwickelte. Hier nun das Ergebnis.
!!Nachbau wie immer auf eigene Gefahr!!
Ablaufplan
Erweitert wurde der Ablaufplan durch eine anfängliche Abfrage, ob sich der Füllstand geändert hat.
Ist aber der maximale Füllstand erreicht, läuft die Routine bis entweder der Füllstand nach Abpumpen erreicht oder manuell eingegriffen wird.
Benötigte Bauteile:
- 1 x ESP8266 (NodeMCU V3)
- 1 x Netzteil 9V
- 1 x Netzteil 5V
- 2 x LED (1 x rot, 1 x grün)
- 2 x Widerstand 220 Ohm
- 1 x Ultraschallmodul HC-SR04
- 1 x Relaismodul
- 1 x OLED-Display 0,96″
- 1 x Pumpe (säurebeständig, Kondensat aus Kaminen sind schwefelhaltig)
- 1 x Kunstoffbox zum Auffangen des Kondensats
- 3D-Ausdruck Gehäuse (Eigenkonstruktion)
- 3D-Ausdruck Steg mit Deckel über Box (Eigenkonstruktion)
- 3D-Ausdruck Gehäuse für Relais-Modul
- diverse Kabel und Litzen für Stromversorgung und Zusammenbau
- Teilstück 3-Loch-Streifenrasterplatine
Versuchsaufbau
/*********
Michael Wiesner
Complete project details at https://4bastler.de
Ultraschall-Sensor und Relaismodul
*********/
//WiFi-Verbindung
#include <ESP8266WiFi.h>
//Display
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
//Zeitserver
#include <NTPClient.h>
#include <WiFiUdp.h>
//WLAN-Daten
const char* ssid = "Deine SSID";
const char* password = "Dein Passwort für das WLAN";
// Web Server Port 80 definieren
WiFiServer server(80);
//Zeitserver
//Zeitverschiebung UTC <-> MEZ (Winterzeit) = 3600 Sekunden (1 Stunde)
//Zeitverschiebung UTC <-> MEZ (Sommerzeit) = 7200 Sekunden (2 Stunden)
const long utcOffsetInSeconds = 3600;
char daysOfTheWeek[7][12] = {"Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"};
//Zeitserver
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", utcOffsetInSeconds);
//Display
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
//Variablen
//Variablen Serveraufruf
const char* host = "Hier die IP eurer Steuereinheit einsetzen";
String text1 = "Initialisiere";
String text2 = "Initialisiere";
String textf1 = "Initialisiere";
String textf2 = "Initialisiere";
int dlauf1 = 0;
int Zeile1x = 0;
int Zeile1y = 0;
int Zeile2x = 0;
int Zeile2y = 25;
int Zeile3x = 0;
int Zeile3y = 35;
const int echoPin = 0; //D3
// const int trigPin = 2; //D4
const int minDist = 6; //Mindestabstand in cm
const int anzPinMin = 12; // D6 Anzeige ob Mindestabstand unterschritten
const int maxDist = 12; //Mindestabstand in cm
const int anzPinMax = 13; // D7 Anzeige ob Maxabstand unterschritten
const int alarmDist = 4; //Mindestabstand in cm
const int anzPinAlarm = 13; //Anzeige ob Pumpe nicht geschaltet wurde
const int schaltPinPumpe = 15;
long duration;
int distance;
int distanceold = 17;
//Funktionen
int abstandmessen ()
{
const int trigPin = 2; //D4
pinMode(trigPin, OUTPUT);
int abstand = 0;
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
duration = pulseIn(echoPin, HIGH);
abstand = duration * 0.034 / 2;
return abstand;
}
//Ende Funktionen
void setup()
{
pinMode(echoPin, INPUT);
//LED-Anzeige
pinMode(anzPinMin, OUTPUT);
pinMode(anzPinMax, OUTPUT);
//Pumpe
pinMode(schaltPinPumpe, OUTPUT);
Serial.begin(115200);
digitalWrite(schaltPinPumpe, LOW);
digitalWrite(anzPinMin, LOW);
digitalWrite(anzPinMax, HIGH);
//WLAN verbinden
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
//Starten des Webservers
server.begin();
Serial.println("Web server running. Waiting for the ESP IP...");
delay(200);
//Zeitserver starten
timeClient.begin();
// Printing the ESP IP address
Serial.println(WiFi.localIP());
timeClient.update();
//Display
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3D for 128x64
Serial.println(F("SSD1306 allocation failed"));
for(;;);
}
delay(100);
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(WHITE);
display.setCursor(0, 25);
// Display static text
display.println("Starte");
display.println("test");
display.display();
delay(1500);
}
void loop()
{
if (dlauf1 == 0) //Display 1ter Durchlauf
{
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0, 10);
display.display();
dlauf1 = 1;
}
//Zeitserver aktualisieren
timeClient.update();
display.setCursor(Zeile1x, Zeile1y);
display.fillRect(0, Zeile1y, 128, 10, BLACK);
// Display static text
display.setTextSize(1);
display.println(timeClient.getFormattedTime());
display.println(WiFi.localIP());
display.display();
distance = abstandmessen();
Serial.print("Distance: ");
Serial.println(distance);
if(distanceold != distance)
{
if(distance < minDist)
{
//Pumpe an
digitalWrite(schaltPinPumpe, HIGH);
//Display
display.setCursor(Zeile3x, Zeile3y);
display.fillRect(0, Zeile3y, 128, 30, BLACK);
// Display static text
display.setTextSize(3);
display.println(distance);
display.display();
digitalWrite(anzPinMin, HIGH);
digitalWrite(anzPinMax, LOW);
while(distance < maxDist)
{
distance = abstandmessen();
Serial.print("Distance: ");
Serial.println(distance);
//Display
display.setCursor(Zeile3x, Zeile3y);
display.fillRect(0, Zeile3y, 128, 30, BLACK);
// Display static text
display.setTextSize(3);
display.println(distance);
display.display();
//Alarmfunktion
while(distance<alarmDist)
{
distance = abstandmessen();
Serial.print("Distance: ");
Serial.println(distance);
//Display
display.setCursor(Zeile3x, Zeile3y);
display.fillRect(0, Zeile3y, 128, 30, BLACK);
// Display static text
display.setTextSize(3);
display.println("Alarm");
display.display();
//LED blinken lassen
digitalWrite(anzPinMin, HIGH);
delay(500);
digitalWrite(anzPinMin, LOW);
delay(300);
//Speicherung Daten
// We now create a URI for the request
String url2 = "PfadzumVerarbeitender Daten?var1=Name&distance=";
url2 += distance;
delay(1000);
Serial.print("Requesting URL: ");
Serial.println(url2);
//Daten auf Krake speichern
// Use WiFiClient class to create TCP connections
WiFiClient client;
//const int httpPort = 80;
if (!client.connect(host, 80)) {
Serial.println("connection failed");
return;
}
// This will send the request to the server
client.print(String("GET ") + url2 + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n"+
"Connection: close\r\n\r\n");
//Ende Speicherung Daten
}
//Display
display.setCursor(Zeile3x, Zeile3y);
display.fillRect(0, Zeile3y, 128, 30, BLACK);
// Display static text
display.setTextSize(3);
display.println(distance);
display.display();
//Speicherung Daten
// We now create a URI for the request
String url2 = "PfadzumVerarbeitender Daten?var1=Name&distance=";
url2 += distance;
delay(1000);
Serial.print("Requesting URL: ");
Serial.println(url2);
//Daten auf Krake speichern
// Use WiFiClient class to create TCP connections
WiFiClient client;
//const int httpPort = 80;
if (!client.connect(host, 80)) {
Serial.println("connection failed");
return;
}
// This will send the request to the server
client.print(String("GET ") + url2 + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n"+
"Connection: close\r\n\r\n");
//Ende Speicherung Daten
}
//Pumpe aus
digitalWrite(schaltPinPumpe, LOW);
digitalWrite(anzPinMin, LOW);
digitalWrite(anzPinMax, HIGH);
}
//Display
display.setCursor(Zeile3x, Zeile3y);
display.fillRect(0, Zeile3y, 128, 30, BLACK);
// Display static text
display.setTextSize(3);
display.println(distance);
display.display();
//Speicherung Daten
// We now create a URI for the request
String url2 = "PfadzumVerarbeitender Daten?var1=Name&distance=";
url2 += distance;
delay(1000);
Serial.print("Requesting URL: ");
Serial.println(url2);
//Daten auf Krake speichern
// Use WiFiClient class to create TCP connections
WiFiClient client;
//const int httpPort = 80;
if (!client.connect(host, 80)) {
Serial.println("connection failed");
return;
}
// This will send the request to the server
client.print(String("GET ") + url2 + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n"+
"Connection: close\r\n\r\n");
//Ende Speicherung Daten
distanceold = distance;
}
}
Der Quellcode ist eine erste Programmierung und natürlich noch optimierungsbedürftig.
Aber das Wichtige für mich:
Er funktioniert:
Er gibt mir den Füllstand aus und eine Alarmierung, wenn nicht gepumpt wird und der Behälter droht überzulaufen.
Schwefelbelastetes Wasser im Keller ist nicht wirklich wünschenswert.
Die Umsetzung
Das Auffangbecken wird vom Anschluss her definitiv überarbeitet. Die Lüsterklemme wird bei nächster Gelegenheit gegen eine professionelle Lösung ersetzt.