Beim letzten Starkregen (welcher in Deutschland ja verheerende Schäden angerichtet hat) kam auch bei uns die Kanalisation nicht mehr mit. Gott sei Dank gab es nicht so große Probleme wie anderswo, aber unsere Zisterne ist übergelaufen und dadurch ist mein Sensor in der Zisterne abgesoffen.

Durch Wasser zerstörter Zisternensensor
Durch Wasser zerstörter Zisternen-Sensor

Interessanterweise läuft der ESP8266 noch problemlos, aber die Messung liefert Mondwerte.

Mein Plan ist Elektronik und Sensor wieder zu trennen. Der Sensor wird in der Zisterne versenkt, die Elektronik kommt ins Pumpenhaus.

Wasserstandssensor auf Druckbasis mit Stromschleife
Wasserstandssensor auf Druckbasis mit Stromschleife

Doch wie bringt man einem ESP8266 bei Strom zu messen? Sicher gibt es viele Möglichkeiten, doch ich entscheide mich ganz simpel für einen (passenden) Widerstand, an dem die gewünschte Spannung abfällt.

Wir erinnern uns kurz zurück an die Schule: Da war mal was das hieß “U = I * R”
Und ich möchte das an meinem ADC, wenn der Sensor 20mA liefert eine Spannung von 3.3V anliegt. Das ist die Betriebsspannung meines ESP8266.
Das heißt: R = 3,3V / 0,020A = 165 Ohm -> Ich nehme also einen 150 Ohm Widerstand.
Bei minimaler und maximaler Wassertiefe (= Stromfluss) ergeben sich dann folgende Spannungen.
V = 0,004A * 150 Ohm = 0,6V (minimal)
V = 0,020A * 150 Ohm = 3,0V (maximal)
Das passt also, auch wenn ich nicht den ganzen Messbereich des ADC ausschöpfe!

Jetzt möchte ich den µC noch gegen Spannungen die größer als VCC (=3,3V) + 0.6V sind schützen und den Strom auf unter 0,1mA bringen. Kann ja immer mal passieren das irgendwo ein Kurzschluss entsteht oder beim Aufbau Kabel vertauscht werden.
R= (24V-(3,3V+0,6V)) / 0,0009A = 22333 Ohm -> Ich nehme also einen 27k Widerstand.

So sieht die modifizierte Schaltung nun aus:

Schaltplan des neuen Zisternen-Sensors mit Wasserdrucksensor
Schaltplan des neuen Zisternen-Elektronik mit Wasserdrucksensor.
Wichtig: Die GNDs der beiden Spannungsquellen sind verbunden! (auf dem Schaltplan nicht zu sehen)

Jetzt schaut man sich den Schaltplan an und denkt: Ok, R2 = 27kOhm, das ist also der Schutzwiderstand.
Aber sollte R3 lt. Berechnung nicht 150 Ohm sein? Warum steht im Schaltplan 50 Ohm?
Das liegt daran, das ich in die Falle meines ESP-Moduls getappt bin. Nachdem ich das so gebaut hatte und der ADC irgendwie nichts sinnvolles gemessen hat, habe ich etwas Datenblätter gewälzt und festgestellt, das die “rohen” ESP-Module – wie ich sie verwende – einen Spannungsbereich am ADC von 0-1V erwarten (trotz 3,3V Betriebsspannung). Es gibt Module da ist direkt ein Spannungsteiler eingebaut, bei meinem nackten Modul aber nicht.

Also nochmal neu gerechnet:
R = 1.0V / 0,020A = 50 Ohm -> Ich nehme also einen 51 Ohm Widerstand.
Der Schutzwiderstand bleibt gleich.
Proberechnung:
V = 0,004A * 50 Ohm = 0,2V (minimal)
V = 0,020A * 50 Ohm = 1,0V (maximal) (hier liefert der ADC dann den Wert 1023)

Neue Schaltung auf Lochrasterplatine
Neue Schaltung auf Lochrasterplatine

Man sieht meine geliebte (aber sehr labile) Wurfverkabelung, mit der ich quasi immer arbeite. 😉
Im Hintergrund ist der USB->Seriell Konverter zu sehen (zum Programmieren) und vorne links, unter der Platine ist der Step-Up-Wandler. Die Platine ist jetzt durch das aus- und einlöten diverser Bauteile ganz schön verbraten, aber muss ja auch keinen Schönheitspreis gewinnen.

Ordentlich verpackt in eine Abzweigdose die rumlag sieht es dann so aus.

Schaltung in Abzweigdose
Schaltung in Abzweigdose

Wie man sieht habe ich das Kabel vom Sensor mit einem Hohlstecker versehen, damit ich die Elektronik für Wartungszwecke leicht vom Sensor trennen kann.

Jetzt fehlt noch der angepasste Arduino Sketch:

#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>

const int sensorEnable = 15; // PIN für den Transistor zum aktivieren des Step-Up-Wandlers
const byte sensorPin = A0; // ADC für den sensor
const uint16_t resistor = 51; // Eingesetzter Pull-Down Widerstand
const int maxAdcWennVoll = 472; // Prozentuale Umrechnung

ESP8266WebServer server(80); // Webserver
WiFiClient client;

              
void setup() {
  Serial.begin(115200);

  IPAddress ip(192, 168, X, Y);
  IPAddress gateway(192, 168, X, Z); 
  IPAddress subnet(255, 255, 255, 0); 
  WiFi.config(ip, gateway, subnet);
  WiFi.begin("**netzwerk**", "**geheim**");

  Serial.print("Connecting");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println();

  Serial.print("Connected, IP address: ");
  Serial.println(WiFi.localIP());  

  server.on("/", handle_normal);
  server.on("/hs", handle_hs);
  server.on("/hs/1", handle_hs);
  server.onNotFound(handle_NotFound);  
  server.begin();
  Serial.println("http server startet");

  pinMode(sensorEnable, OUTPUT);
  digitalWrite(sensorEnable, LOW);
  
  pinMode(sensorPin, INPUT); 
}

void loop() {
  server.handleClient();
}

void handle_NotFound(){
  server.send(404, "text/plain", "Not found");
}

void handle_normal() {
  Serial.println("handle /");
  long pressure = measurePressure();  
  long percent = pressure * 100 / maxAdcWennVoll; //umrechnen auf prozent
  
  String msg = String("<!DOCTYPE html><html>") + 
    "<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">" + 
    "<link rel=\"icon\" href=\"data:,\">" + 
    "<body><h1>Zisterne Measusement Server</h1>" + 
    "<p>Use get parameter hs for homeserver</p>" + 
    "<p>Exampe: /hs/1</p>" + 
    "<br><br><p>Current pressure: " + String(pressure) + "</p>" + 
    "<br><br><p>Current percent: " + String(percent) + "</p>" + 
    "</body></html>\r\n" ;
  server.send(200, "text/html", msg); 
}

void handle_hs() {
  Serial.println("handle /hs");
  long pressure = measurePressure();
  long percent = pressure * 100 / maxAdcWennVoll; //umrechnen auf prozent
  String msg = String("D=" + String(percent) + "\r\n");
  server.send(200, "text/html", msg); 
} 

int measurePressure() {
  Serial.println("setting 24v on");
  digitalWrite(sensorEnable, HIGH);
  delay(5*1000); //auf sensor warten
  
  Serial.println("start measuring");
  int myValue = doMeasure(); 
  Serial.println("done measuring");
  
  Serial.println("setting 24v off");
  digitalWrite(sensorEnable, LOW);
  return myValue;
}

int32_t doMeasure() {
  float minAdc = 0.004 * resistor * 1024;
  float maxAdc = 0.020 * resistor * 1024;
  
  int adc = 0;
  for (byte i = 0; i < 3; i++)
  {
    int m = analogRead(sensorPin);
    Serial.println("adc" + String(m));
    adc += m;    
    delay(10);
  }
  adc = adc / 3;
  int32_t value = (adc - minAdc) * int32_t(1023) / (maxAdc - minAdc);
  if (value > 1023) value = 1023;
  else if (value < 0) value = 0;
  return  value;
}

Ich hoffe das diese Version jetzt rebust genug ist und der China-Sensor auch ein paar Jahre durchhält.

Und wieder habe ich Probleme mit der Füllstandsmessung in meiner Regenwasser Zisterne. Diesmal liegt es am Kabel vom Abstandssensor in der Zisterne bis zur eigentlichen Elektronik, die im Pumpenhaus ist.

Also wieder ein Projekt dazwischen geschoben…

Zuerst habe ich mir überlegt, die ganze Elektronik, also Sensor und ESP8266 in die Zisterne zu packen. Dazu brauche ich natürlich ein möglichst Wasserdichtes Gehäuse. Ich habe mir etwas entsprechendes schnell in 3D entworfen und ausgedruckt. Auch sind die zuletzt von mir montierten Gewindestangen beim reinigen des Schmutzkorbes irgendwie immer im Weg. Darum habe ich mir eine Rohrschelle besorgt, so dass ich mein Gehäuse mit einer Schraube direkt an einem der Rohre befestigen kann.

Hier auch wie immer die STL-Dateien für das Gehäuse.

Auch habe ich die Verbindung zwischen Platine und Sensor nun mit einem Stecker gelöst. Sollte der Sensor also wieder einmal rosten, kann ich ihn einfach durch einen neuen ersetzen.

Die eigentliche Steuerplatine mit dem ESP8266 habe ich im Gehäuse dann einfach darüber gelegt. Auf dem Bild ist rechts auch der neue Stromanschluss zu sehen. Diesmal als Steckverbindung und mit ordentlich Schrumpfschlauch schön wasserfest gemacht.

ESP8266 Elektronik mit Abstandssensor im Gehäuse
Elektronik im Gehäuse

Dann das Gehäuse mit einer M8 Schraube an der Rohrschelle befestigt und den Deckel mit M3 Gewindeschrauben auf das Gehäuse geschraubt. Nicht zu fest anziehen, sonst bricht der Kunststoff…

Gehäuse an Rohrschelle mit zugeschraubtem Deckel
Zugeschraubtes Gehäuse an Rohrschelle

Dann habe ich das ganze wie geplant an einem der KG Rohre in der Zisterne, kurz über der maximalen Wasserhöhe montiert und den vorher verlegten Stromstecker angeschlossen.

Abstandssensor montiert an Rohrschelle in Zisterne
Sensor in Zisterne

Das eigentliche Netzteil ist im Pumpenhaus geblieben. Zur Sicherheit habe ich dort noch einen 1 Ampere Sicherungsautomaten zwischen geschaltet. Nur für den Fall, das es bei der Elektronik doch einen Wasserschaden gibt, will ich nicht das mein Steckernetzteil “abbrennt”.

1A Sicherung im Pumpenhaus

Bei der Überarbeitung der Wasserstandsmessung habe ich auch die Software auf dem ESP8266 aktualisiert:
– Umstellung auf ESP8266WebServer
– Daten werden nicht mehr zum Homeserver gepusht, sondern dieser kann sich die Daten über eine URL abholen (pull)
– Kleine Internetseite zu Diagnosezwecken gemacht
– Messroutine ist geblieben

// Zisterne3.0.ino
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>

const int pingPin = 14; // Trigg
const int start_signal = 12; // Echo
const long middles = 5; // Mittelwerte

ESP8266WebServer server(80); // Webserver
WiFiClient client;

              
void setup() {
  Serial.begin(115200);

  IPAddress ip(192, 168, X, Y);
  IPAddress gateway(192, 168, X, Z); 
  IPAddress subnet(255, 255, 255, 0); 
  WiFi.config(ip, gateway, subnet);
  WiFi.begin("SSID", "PWD");

  Serial.print("Connecting");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println();

  Serial.print("Connected, IP address: ");
  Serial.println(WiFi.localIP());  

  server.on("/", handle_normal);
  server.on("/hs", handle_hs);
  server.on("/hs/1", handle_hs);
  server.onNotFound(handle_NotFound);  
  server.begin();
  Serial.println("http server startet");
}


void loop() {
  server.handleClient();
}

void handle_NotFound(){
  server.send(404, "text/plain", "Not found");
}

void handle_normal() {
  Serial.println("handle /");
  long distance = measureMiddle();
  String msg = String("<!DOCTYPE html><html>") + 
    "<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">" + 
    "<link rel=\"icon\" href=\"data:,\">" + 
    "<body><h1>Zisterne F&uuml;llstand Server</h1>" + 
    "<p>Example for simple output: /hs/1</p>" + 
    "<br><p>Current distance: " + String(distance) + "</p>" + 
    "</body></html>\r\n" ;
  server.send(200, "text/html", msg); 
}

void handle_hs() {
  Serial.println("handle /hs");
  long distance = measureMiddle();
  String msg = String("D=" + String(distance) + "\r\n");
  server.send(200, "text/html", msg); 
} 

long measureMiddle() {
    Serial.println("measuering");
    long distance, i; 
    distance = 0;
    for (i = 0 ; i <= middles ; i++) {
      distance = distance + doMeasure();
    } 
    distance = distance / middles;  

    Serial.println(distance);

    return (distance);    
}

long doMeasure() {
  long duration;

  pinMode(pingPin,OUTPUT);
  pinMode(start_signal,OUTPUT);
  digitalWrite(start_signal,HIGH);
  delayMicroseconds(20);
  digitalWrite(start_signal,LOW);
  digitalWrite(pingPin,LOW);
  delayMicroseconds(2);
  digitalWrite(pingPin,HIGH);
  delayMicroseconds(5);
  digitalWrite(pingPin,LOW);
  pinMode(pingPin,INPUT);  
  duration = pulseIn(pingPin,HIGH);
  delay(80);
  return (microsecondsToCentimeters(duration));
}
 
long microsecondsToCentimeters (long microseconds) {
  return microseconds  / 29 / 2;
}

Dadurch ist der Code auch deutlich aufgeräumter und übersichtlicher geworden.

Die Logik im Homeserver um die Webseite regelmäßig zu laden ist sehr einfach.

Logik für regelmäßigen Aufruf der Internetseite vom Gira Homeserver
Logik für regelmäßígen Aufruf der Internetseite

Ich nutze einfach den Telegrammgenerator um alle 60 Sekunden die Webseite abzurufen. Ich habe das generisch umgesetzt, da ich plane alle ESP8266 Sensoren auf diese Technik umzubauen.
Unterhalb des Telegrammgenerators ist die Umrechnung von der Füllhöhe auf eine Prozentanzeige zu sehen.

Wie ist immer so ist im Leben: Man kann noch so viel planen, irgendwas kommt immer dazwischen und wirft alles wieder durcheinander. 😉

So auch dieses Projekt, denn:
Mein Zisternen-Sensor hat einen Wasserschaden!

Wasserschaden HC-ST04 Ultraschall Abstandssensor
Wasserschaden am HC-ST04 Ultraschall Abstandssensor.

Das kommt daher, dass sich am Deckel über dem Sensor Kondenswasser bildet und dann auf den Sensor tropft. Das ist auch wohl schon im Winter passiert, so durchgerostet wie einige Teile des Sensor-Moduls sind.

Da ich den Sensor nun erneuern muss, bot sich auch die Gelegenheit gleich noch ein paar Dinge mit zu verbessern:

  • Die Halterung. Diese muss jetzt ja auch vor Wasser von oben schützen
  • Außerdem war der Sensor sehr nah über dem Saugschlauch montiert, das brachte die Messung hin und wieder durcheinander.
  • Und dann muss man ja auch alle paar Wochen noch den Schmutz-Fang-Korb sauber machen. Also wollte ich die Kabel steckbar machen um die Wartung zu erleichtern.

Zunächt also musste ein neuer Sensor her. Wie schon zuletzt habe ich einen HC-SR04 besorgt. Diesmal als Set – man weiß ja nie. 😉

Dann habe ich eine neue Halterung entworfen und ausgedruckt. Diesmal mit Deckel und auch etwas näher an der Wasseroberfläche montiert. Es sind drei Teile: Einmal die Halterung, dann der Deckel und dann der Haltewinkel für die Metallschiene swe Zisterne. Alles werde ich mit 6mm Gewindestangen verbinden. Hier gibts auch die .STL Datei.

Zisternen Sensor Halterung 2.0
Neue Halterung für Abstandssensor

Doch bevor ich alles zusammenbaue, hier nochmal die Einzelteile:

Einzelteile Halterung 2.0
Einzelteile Halterung 2.0, M6 Muttern, Unterlegscheiben, Gewindestangen und die gedruckten Halterungen.

Dann habe ich erstmal gelötet und das Kabel bzw. Sensor mit Pfostensteckern versehen. So kann ich das Kabel ganz leicht vom Sensor oder von der Basis trennen.

Und montiert in der Zisterne sieht es dann so aus. Denke, das ist deutlich professioneller als mit der alten Halterung. Und ich hoffe das “Dach” schützt den Sensor ausreichend.

Montierter Abstandssensor in Zisterne
Montierter Abstandssensor in Zisterne