BWT Aqua Smart Wasserzähler auslesen

Die BWT Aqua Smart Entärtungsanlage hat einen eingebauten Wasserzähler. Der wird benutzt um die Harzpatrone, mit der die eigentliche Enthärtung durchgeführt wird, nur dann zu regenerieren, wenn es wirklich nötig ist. Meinen Hauptwasserzähler wollte ich schon früher für die Heimautomatisierung auslesen, habe das Vorhaben dann aber aus folgenden Gründen verworfen:

  1. Der bei mir installierte Zähler war nur schlecht dazu geeignet, ausgelesen zu werden. Es war kein rotierender Magnet zu finden, den man per Reedkontakt auslesen könnte, und auch optisch war es sehr schwierig, das kleine drehende Zahnrad sauber zu erfassen.

  2. Die Wasserzähler werden regelmäßig getauscht, d.h., mit etwas Pech hätte jede noch so gute Lösung nach kurzer Zeit wieder hinfällig sein können.

Also habe ich mal den linken Plastikdeckel des BWT Aquasmart entfernt und ein Mini-Oszilloskop an den zweipoligen Stecker gehängt: man konnte (bei Durchfluss) ein Rechtecksignal sehen, mit ca. 3.3V.

Wemos D1 Mini Steckerblegung

Da ich die über 2000€ teure Anlage in der Garantiezeit nicht zerstören wollte, bin ich dann erstmal mit einem Optokoppler drangegangen; leider hatte der Ausgang des Durchflusszählers nicht genügend Leistung, meinen Optokoppler zu treiben.

Adapterkabel

Da die Eingänge eines ESP8266 nur sehr wenig Leistung brauchen, und da sowohl die BWT als auch ein per USB-Netzteil versorgter Wemos D1 Mini praktisch potentialfrei sind, habe ich dann einfach den Ground des Wemos über 1kΩ mit dem Ground der BWT verbunden, und die Digitaleingang über 1kΩ mit dem Ausgang des Wasserzählers. Das lief nur mäßig stabil, aber als ich beide Widerstände gegen 120Ω getauscht habe, lief es gut.

Aus einer alten Platine konnte ich noch passende Stecker und Buchsen rauslöten, um ein kleines Abgreifkabel zu bauen. Damit kann ich meine Messvorrichung leicht ausbauen, falls doch mal ein Garantiefall eintreten sollte. Falls ich die Bezeichnung der Stecker noch rausfinde, trage ich das hier nach!

Zwischenstecker

ESP-Quellcode

Hier erstmal der Code, der auf dem Wemos läuft, um die Pulse zu erkennen und auszulesen. Vieles ist Debugcode, der eigentlich weg kann. Den Uptime-Zähler habe ich reingemacht, weil der ESP zuerst oft Neustarts gemacht hat, die ich sauber erkennen wollte. Außerdem ist noch eine OTA-Updatemöglichkeit drin, damit ich bei Änderungen nicht mehr an die Hardware dran muss.

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

const char* ssid = "WLAN-Name";
const char* password = "WLAN-Passwort;

ESP8266WebServer httpServer(80);
ESP8266HTTPUpdateServer httpUpdater;

const int ledPin =  LED_BUILTIN;// the number of the LED pin
const byte interruptPin = D1;
volatile unsigned long alteZeit=0, entprellZeit=10,  interruptCounter = 0;

void handleInterrupt() {
  if((millis() - alteZeit) > entprellZeit) { 
    // innerhalb der entprellZeit nichts machen
    interruptCounter++;
    digitalWrite(ledPin, digitalRead(interruptPin)); // LED umschalten
    alteZeit = millis(); // letzte Schaltzeit merken
  }
}

String uptime() {
 String s = "";
 long days=0;
 long hours=0;
 long mins=0;
 long secs=0;
 secs = millis()/1000; //convect milliseconds to seconds
 mins=secs/60; //convert seconds to minutes
 hours=mins/60; //convert minutes to hours
 days=hours/24; //convert hours to days
 secs=secs-(mins*60); //subtract the coverted seconds to minutes in order to display 59 secs max
 mins=mins-(hours*60); //subtract the coverted minutes to hours in order to display 59 minutes max
 hours=hours-(days*24); //subtract the coverted hours to days in order to display 23 hours max

 if (days>0) {
  s = String(days) + " days ";
 }
 s += String(hours) + ":" + String(mins) + ":" + String(secs);

 return s;
}

String site;

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

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  while(WiFi.waitForConnectResult() != WL_CONNECTED){
    WiFi.begin(ssid, password);
  }

  pinMode(ledPin, OUTPUT);
  pinMode(interruptPin, INPUT_PULLUP);
  //pinMode(interruptPin, INPUT);
  attachInterrupt(digitalPinToInterrupt(interruptPin), handleInterrupt, CHANGE);

  site = "<html><head><title>Enthaertungsanlage</title><meta http-equiv='refresh' content='1' /></head><body>";
  site += "<h1>Enthaertungsanlage</h1>";
  site += "<p>Version vom: " __DATE__ " " __TIME__  "</p>";
  site += "<p>Reset Reason: " + ESP.getResetInfo() + "</p>";
  site += "<p>Input: " + String(digitalRead(interruptPin)) + "</p>";
  httpServer.on("/", [](){
    
    httpServer.send(200, "text/html", site  + "<p>" + uptime() + "</p>\n" + String(interruptCounter * 0.0069) + "l<p/></body></html>");
  });
//  httpServer.on("/get-and-reset", []() {
//    unsigned long tmp = interruptCounter;
//    interruptCounter = 0;
//    httpServer.send(200, "text/html", String(tmp * 0.0069)); 
//  });
  httpServer.on("/get", []() {
    httpServer.send(200, "text/html", "Counter: " + String(interruptCounter) + "\n"); 
  });


  httpUpdater.setup(&httpServer);
  httpServer.begin();
}

void loop(void){
  httpServer.handleClient();
  //delay(200);
}

Kalibrierung

Die Kalibrierung hat sich schwieriger gestaltet als ich erwartet hätte. Denn ähnlich wie bei meinem Hauptwasserzähler ist das Zählwerk recht träge. D.h., wenn man den Hahn kurz auf- und wieder zumacht, kommen noch sehr lange nach dem Schließen des Hahns Impulse. Ich habe dann einige Kalibrierdurchläufe mit einem Litermessbecher gemacht - wenn jemand genauere Kalibrierwerte hinbekommt, wäre ich dafür sehr dankbar. Mein bester Wert waren dann 0,0069 Liter pro Impuls.

Auswertung in FHEM

In der FHEM.cfg habe ich im Endeffekt folgendes hinzugefügt:

define Enthaertungsanlage HTTPMOD http://ESP-00A746.fritz.box/get 60
attr Enthaertungsanlage userattr reading01Name reading01OExpr reading01Regex
attr Enthaertungsanlage enableControlSet 1
attr Enthaertungsanlage event-on-change-reading .*
attr Enthaertungsanlage reading01Name Counter
attr Enthaertungsanlage reading01OExpr $val * 0.0069
attr Enthaertungsanlage reading01Regex Counter:.(\d+)
attr Enthaertungsanlage room Heizraum

define Plot_Enthaertungsanlage SVG lp:Plot_Enthaertungsanlage:CURRENT
attr Plot_Enthaertungsanlage label "Enthärtungsanlage Min $data{min1}l/min, Max $data{max1}l/min, Aktuell $data{currval1}l/min"
attr Plot_Enthaertungsanlage room Heizraum

Wenn ihr nicht dbLog benutzt, müsst ihr halt noch ein entsprechendes Logfile anlagen. Das Plot-File in www/gplot/Plot_Enthaertungsanlage.gplot sieht so aus (da stimmen die Offsets bei den Deltas manchmal nicht so richtig, da wäre ich auch für Tipps dankbar!):

# Created by FHEM/98_SVG.pm, 2018-03-04 14:56:02
set terminal png transparent size <SIZE> crop
set output '<OUT>.png'
set xdata time
set timefmt "%Y-%m-%d_%H:%M:%S"
set xlabel " "
set title '<L1>'
set ytics 
set y2tics 
set grid ytics
set ylabel "Verbrauch pro Stunde"
set y2label "Verbrauch pro Tag"
set yrange [0:200]
set y2range [0:400]

#lp DbLog:logdb,extend=86400:Enthaertungsanlage:Counter::delta-h
#lp DbLog:logdb,extend=2:Enthaertungsanlage:Counter::delta-d

plot "<IN>" using 1:2 axes x1y1 title 'Frischwasser pro Stunde' ls
l2fill lw 1 with histeps,\
     "<IN>" using 1:2 axes x1y2 title 'Frischwasser pro Tag' ls l3fill
	 lw 0.5 with histeps
	 

Im Endeffekt sieht das für einen Tag dann so aus:

Plot 24 Stunden

Und für eine ganze Woche so:

Plot Woche

ToDo

Die Enthärtungsanlage war mein letzes Bastelprojekt, bevor ich mich mit MQTT genauer auseinandergesetzt habe. Mittlerweile binde ich sämtliche Sensoren ausschließlich über MQTT ein, und ich habe auch geplant, das bei diesem Sensor noch nachzuholen.

Fragen, Ideen, Ergänzungen, Anregungen?

Ich bin über Feedback dankbar! Schreibt an blog@tobox.de