Table of Contents

Wasserstandsmesser

Motivation

Unsere Wasserversorgung hier in Thailand kommt aus dem Tiefbrunnen (120m) und wird in zwei Tanks (1000l + 2000l) gespeichert. Dazu gesellt sich ein 1000l Tank als Ausgleichsbehälter für den Pool. Die Füllstände aller Tanks werden über mechanische Schwimmschalter gesteuert, die die jeweiligen Pumpen bei Bedarf einschalten. Das funktioniert meist zuverlässig aber eine aktuelle Füllstandsanzeige wäre schon hilfreich. Vor allem wenn man sich schon mit Home Assistant einem Smart Home annähert. Ein Füllstandsmesser muss her.

water tanks

Lösungsansatz

Fertige Lösungen sind wie immer sehr teuer und ausserdem ist ja auch der Weg das Ziel. Eine mechanische Lösung habe ich von vorne herein ausgeschlossen um wartungsfrei zu bleiben, Auch wollte ich keine Lösung, wo ich die Tanks unterhalb der max. Wasserstandshöhe anbohren muss und dann die Abdichtung ein Problem werden kann. Da die Geometrie der Tanks bekannt ist, bietet sich eine Ultraschall-Abstandsmessung der Wasseroberfläche an. Selbst während des Pumpvorganges ist die Wasseroberfläche nicht so rau, das es zu deutlichen Fehlmessungen kommen wird. Beispiele für DIY Lösungen sind auch hier zu finden (teilweise nach meiner Implementierung in 2021 erschienen):

Da wir es hier ja mit Wasser zu tun haben, scheidet das verbreitete, preiswerte Ultraschallmodul HC-SR04 aus. Aber es gibt ein ähnliches, wasserfestes Modul AJ-SR04M.

HC-SR04

AJ-SR04M

Das AJ-SR04M Modul hat einige gute Eigenschaften:

  1. wasserfester Sensorkopf
  2. Messbereich von 20cm bis 450cm
  3. gute Auflösung von 0.5cm
  4. fünf Betriebsmodi (pulse width (default), low power pulse width, automatic serial port, serial port trigger, ASCII code output)
  5. geringe Stromaufnahme im Ruhebetrieb (<20µA)

Vom HC-SR04 Modul kennen wir die Pulseweitenmessung. Zur Bestimmung der Entfernung messen wir die Zeit vom Triggersignal bis zum eintreffenden Echosignal. Das AJ-SR04M Modul hat einen eigenen Microcontroller an Board und bietet diese Zeitmessung an, kann das Ergebnis aber seriell zurückgeben. Das entbindet uns von zeitkritischen Pulsmessungen. Um das Modul in den jeweiligen Betriebsmodus zu bringen muss der Widerstand R19 richtig bestückt werden:

Modus R19 Standby Current Low Power Current
1. Compatible HC-SR04 trigger mode (default) open <2mA -
2. Low Power mode 300kΩ <2mA <40µA
3. Automatic serial port mode 120kΩ <2mA -
4. Low power Serial port mode 47kΩ <2mA <20µA
5. ASCII code output mode 0kΩ <2mA <20µA

 R19 location

Umsetzung

Ich habe mich für den Mode 4 entschieden bei mit der UART serial ein Triggerbyte gesendet wird und anschliessend das Messergebnis seriell empfangen werden kann. Dazu brauchen wir einen 47KΩ Widerstand. Vorgesehen ist eine 0805 Bauform für R19 aber durch die großen Pads läßt sich auch leicht ein bedrahteter Widerstand anlöten.

Serial protocol

Die Baudrate ist übrigens 9600 Baud und nach erfolgter Messung werden fünf Bytes mit folgendem Format übertragen:

// AJ_SR04M_Sensor serial format:
// Trigger: 0x00
// Response: Byte1          Byte2  Byte3  Byte4               Byte5
//           Start Byte=FF  MSB    LSB    Checksum (LSB+MSB)  00

Das Ergebnis ist in Millimeter. Durch den seriellen Ansatz läßt sich der Sensor jetzt mit jedem PC (mit USB-Serial Adapter) oder einem Controller auslesen, der eine UART besitzt. Bisher messen wir nur den Abstand zur Wasseroberfläche. Mit etwas Mathematik können wir den Abstand in eine Literangabe oder einen Prozentwert umrechnen.

Dank an Omar Al-Janabi der die Berechnung schon detailliert beschrieben hat. Zur Berechnung brauchen wir die Tiefe des Tanks T_d in Richtung der Messung. Den Abstand T_e des Sensors vom höchst möglichen Wasserstand (min 20cm gemäß Sensorspezifikation), die Tankkapazität T_c und natürlich den Messwert x. Die Formel lautet dann für die Maßeinheit Zentimeter:

y={{(T_d-T_e) - ((x*100) - T_e)} / {T_d-T_e}} * T_c

In meinem Fall wie weiter unten angegeben gelten folgende Daten für den Wassertank: T_d = 175 cm, T_c = 1000 Liter, T_e = 20 cm (x in Meter)

y={{(175-20) - ((x*100) - 20)} / {175-20}} * 1000

Die Formel läßt sich mit den realen Werten vereinfachen aber wegen dem besseren Verständnis habe ich sie so wie sie ist implementiert.

Home Assistant Integration

Mit einem ESP8266 Modul und ESPHome gelingt die Integration in Home Assistant sehr einfach. Das serielle Protokoll läßt sich am einfachsten mit einem Custom Component auswerten. Das folgende kleine C Programm schreibt das Trigger Byte beim Update Request und berechnet das Messergebnis (in Meter) anhand der empfangenen fünf Bytes.

AJ_SR04M_Sensor.h
#include "esphome.h"
 
class AJ_SR04M_Sensor : public PollingComponent, public UARTDevice, public Sensor {
 public:
 
  AJ_SR04M_Sensor(UARTComponent *parent) : PollingComponent(5000), UARTDevice(parent) {}
 
  void update() override {
 
    char frame[5];
    int pos = 0;
    float value = 0.0;
 
    write(0x00);
    while (available()) {
      frame[pos] = read();
      pos++;
      if(pos==5) {
        if ((frame[0] == 0xFF) && (frame[4] == 0x00) && ((frame[1]+frame[2])==frame[3])) {
          value = ((frame[1]<<8) + frame[2]) / 1000.0;
          publish_state(value);
        }
        break;
      }
    }
  }
};

In ESPHome generieren wir ein neues Device und fügen den eigenen Code mit einem includes hinzu. Das File AJ_SR04M_Sensor.h muss dazu in /config/esphome kopiert werden.

esphome:
  name: water-level-serial
  comment: "Measure water level of water tanks by ultrasonic wave"
  includes:
    - AJ_SR04M_Sensor.h

Dann fügen wir die UART Schnittstelle hinzu. Falls wir keine Pins der Hardware UART verwenden wird automatisch eine Software UART implementiert. Da ich in meiner Lösung insgesamt 3 Module anschließe, gehen mir sowieso die H/W UARTs aus. Zu guter Letzt die Implementierung der Sensoren. Der Sensor mit der ID dist1 gibt die gemessene Distanz in Meter her. Mit Template Sensoren lässt sich dann der Wert wie oben beschrieben in eine Prozent- und Literangabe umrechnen.

uart:
  - id: uart_dist1
    tx_pin: GPIO14
    rx_pin: GPIO12
    baud_rate: 9600

sensor:
  - platform: custom
    lambda: |-
      auto my_sensor = new AJ_SR04M_Sensor(id(uart_dist1));
      App.register_component(my_sensor);
      return {my_sensor};
    sensors:
      unit_of_measurement: m
      accuracy_decimals: 3
      name: "Water Tank Distance"
      id: dist1
  - platform: template
    name: 'Water Tank Level'
    unit_of_measurement: '%'
    accuracy_decimals: 0
    update_interval: 10s
    icon: mdi:water-percent
    lambda: |- 
        return (((175-20)-((id(dist1).state*100)-20))/(175-20))*100;
  - platform: template
    name: 'Water Tank Volume'
    unit_of_measurement: 'l'
    icon: mdi:cup-water
    accuracy_decimals: 0
    update_interval: 10s
    lambda: |-
       return (((175-20)-((id(dist1).state*100)-20))/(175-20))*1000;

Mechanik

Der Sensorkopf hat am Rand Klemmlaschen und ist so für eine Öffnung von ca. 20mm geeignet.

Dimensions

In dünnwandigen Tankgehäusen kann man mit einem passenden Leerrohrverbinder den Sensor stabil einbauen und gleichzeitig das Kabel mit einem Kabelschlauch ummanteln.

PVC Conduit

Hier die Montage oben auf unserem Dwell Tank. Der Sensor ist so gut gegen mechanischen Stress und Umwelteinflüsse geschützt. Bei uns hat er so jetzt schon mehr als 1 Jahr fehlerfrei überstanden.

Mounted on top of the tank

In den meisten Fällen wird wahrscheinlich das 2.5m lange Sensorkabel ausreichen. Bei mir war die Entfernung zu zwei Tanks leider größer. Versuche das Sensorkabel zu verlängern zogen Messungenauigkeiten mit sich. Deshalb habe ich die AJ-Steuerplatine abgesetzt und in einem kleinen, wasserdichten Gehäuse verstaut. Das Bild zeigt nur das innere 3D-gedruckte Gehäuse.

3D printed inner housing

Das ESPHome Modul ist in einem etwas größeren, wasserfesten Gehäuse untergebracht. Das Innenleben ist auf einem 3D-gedruckten Träger untergebracht. Für zwei Wassertanks kommt das serielle Signal über ein 4-adriges Kabel an die Schraubklemmen (der oben gezeigte Adapter ist ja dazwischen)) und der näher gelegene Wassertank wird direkt an das Messmodul angeschlossen. Als Netzteil verwende ich übrigens immer diese Apple-ähnlichen USB Netzteile. Der Eingang wurde von mir auf Schraubklemmen modifiziert. Diese Lösung ist recht zuverlässig, sehr preiswert und sicher da vollkommen gekapselt.

ESPHome module

Ergebnisse

Nach getaner Arbeit kann man jetzt den Füllstand der Tanks beobachten und auch Aktionen daraus ableiten. Hier ein Blick auf das übersichtliche Panel von Home Assistant für den Aussenbereich. Dort werden die Füllstände der Tanks live angezeigt.

Panel screen outdoor

Natürlich kann man sich auch den Verlauf ansehen:

Water level history

Der unterschiedliche Füllstand liegt am manuelle Auffüllen, da der mechanische Endschalter bei der Erstellung des Artikels defekt war.

Spenden

Wenn ihr meine Arbeit unterstützen wollt, so könnt ihr mir gerne einen Cappuccino oder so spenden: .