Zum Hauptinhalt springen

Measure water level in cisterns and tanks with HomeAssistant, ESPHome and TL-136 pressure sensor - UPDATE!

·14 min
En Diy Esphome Home-Assistant Wemos
Autor
Markus

»zur deutschen Version des Beitrags wechseln

Rainwater is now a precious commodity. Last year, we got a 5,000 liter rainwater cistern from Rewatec . Having something like this installed separately and retrospectively just for the rainwater is rarely worthwhile, as the effort and costs are considerable.

During the renovation of our terrace, however, we discovered that our guttering was dilapidated and the excavator was already there anyway, so the cistern could be installed with little effort. The rainwater that falls on the 75 m² south side of the roof now flows into it - if it rains at all …

We feed our Gardena sprinklers from the cistern, which are supplied by a Renkforce submersible pump (which has been in service for 8 years). Of course, you want to know how much water is in the cistern so that you can then control the irrigation. In addition, the submersible pump requires a minimum fill level of 8 cm so that it does not run dry.

DIY solutions mostly unreliable
#

There are some DIY approaches for water level measurement, but they often work rather poorly. Ultrasonic sensors that are directed at the water surface not only suffer from the damp environment and then fail, but often do not measure correctly due to reflections. The same applies to optical TOF (Time of Flight) sensors. Capacitive sensors tend to measure inaccurately, as impurities change the dielectric constant of the water. I also experimented with this, but quickly abandoned it.

Cascades with reed relays and resistors and a float with magnet work well and are robust, but only resolve very coarsely. For a cistern that can reach a maximum level of 1.05 meters, this is rather unsatisfactory.

Floats with pulleys and rope on a potentiometer are too adventurous.

Pressure sensors, on the other hand, are very accurate. Small pressure sensors, such as those built into blood pressure monitors, would be sufficient for the application and are quite inexpensive. However, they do not take into account the variable air pressure acting on the water column and do not provide accurate readings, and the hose to the sensor is also prone to clogging.

TL-136 pressure sensor as a solution
#

Piezoelectric pressure sensors, the TL-136 liquid level transmitters , are not quite as inexpensive, but they are robust and accurate. These also have a small tube in the supply line that allows the external pressure to flow into the measurement. These sensors are available for various filling levels for around 50 euros. For this, you get a solid stainless-steel housing with a very simple control unit. The sensor is simply placed at the bottom of the cistern or tank. I chose the 0-1 meter model because the overflow of my cistern is already at 105 cm. The 0-1 meter model should also be suitable for the popular IBC containers, as you don’t let them fill up to the last centimeter.

The sensor is supplied with 24 volts and converts the pressure in the range 0-20 mA. The current must therefore be measured to calculate the fill level and later the fill quantity. There are inexpensive small modules with a transconductance converter, i.e. the conversion of a current into a voltage. However, you can also simply use a resistor to pick up the dropped voltage.

With a 150 Ohm resistor, the range up to 100 cm can be tapped in such a way that a maximum voltage of 3.2 volts is obtained - ideal for the ADC of an ESP8266 or ESP32. With a 27 kOhm resistor in series to the analog input of the ESP, you have additional protection, as this can tolerate a maximum of 3.3 volts. I still like to use the practical and inexpensive WeMos D1 Mini .

There is also no need to use an additional power supply unit for the 24 V of the sensor. A step-up converter can also be used here and can generate the 24 V from the 5 V pin of the ESP. The step-up converter is set to the required 24 V output voltage BEFORE installation.

In order to find out what voltage is output at what fill level, I put a plug in a 100 mm HT pipe, filled it with water, immersed the sensor to different depths and measured the voltage. The hydrostatic pressure in such a pipe at the same depth is just as high as in a 5,000 liter cistern.

Der ESPHome Code für die Wasserstandsmessung
#

The code for the ESPHome sensor is pretty self-explanatory. The A0 pin, i.e. the analog-digital converter, is read out. Incidentally, the ESP8266 does not output 0 - 3.3 volts here, but 0 - 1 V. That’s why I installed a filter with - multiply: 3.3. The id: levelraw allows me to access the level in centimeters again later in another function.

esphome:
  name: waterking
  platform: ESP8266
  board: d1_mini

# Enable logging
logger:
  baud_rate: 0

# Enable Home Assistant API
api:

ota:
  password: !secret ota password
wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Waterking Fallback Hotspot"
    password: !secret fallback password

captive_portal:

sensor:
  - platform: adc
    pin: A0
    name: "Wasserstandcm"
    id: levelraw
    update_interval: 2s
    filters:
      - multiply: 3.3
      - sliding_window_moving_average:
          window_size: 30
          send_every: 30
      - calibrate_linear:
            - 0.61 -> 0.0
            - 0.76 -> 0.075
            - 0.8 -> 0.09
            - 0.81 -> 0.1
            - 0.8411 -> 0.12
            - 0.99 -> 0.172
            - 1.04 -> 0.22
            - 1.2 -> 0.25
            - 1.8 -> 0.5
            - 2.4 -> 0.75
            - 2.66 -> 0.9
            - 2.983 -> 1.0
            - 3.2 -> 1.19
      - multiply: 100
    accuracy_decimals: 1
    unit_of_measurement: cm
    icon: "mdi:car-coolant-level"

  - platform: adc
    pin: A0
    name: "Zisterne Volt"
    update_interval: 5s
    filters:
      - multiply: 3.3
      - median:
          window_size: 7
          send_every: 4
          send_first_at: 3

  - platform: template
    name: "Zisterne Liter"
    lambda: |-
      return id(levelraw).state;

    filters:
      - calibrate_linear:
          - 4 -> 80
          - 10 -> 200
          - 12.5 -> 300
          - 15 -> 400
          - 17.5 -> 500
          - 20 -> 600
          - 25 -> 850
          - 27.5 -> 1000
          - 40 -> 1700
          - 45 -> 2000
          - 60 -> 3000
          - 70 -> 3600
          - 80 -> 4000
          - 85 -> 4400
          - 90 -> 4700
          - 95 -> 4900
          - 100 -> 5100
    unit_of_measurement: l
    accuracy_decimals: 0

  - platform: template
    name: "Idraw"
    lambda: |-
      return id(levelraw).state;

The median smoothes the values, as the signal is somewhat noisy. I have not yet found out why. The voltage supply of the step-up converter is stable. However, the noise is in the range of 0.5 cm fill level, which is negligible. The accuracy of the sensor itself is specified as 0.2 - 0.5 % FS. At a fill level of 0 - 1 meter, the 0.5 cm noise is exactly 0.5 % …The median smoothes the values, as the signal is somewhat noisy. I have not yet found out why. The voltage supply of the step-up converter is stable. However, the noise is in the range of 0.5 cm fill level, which is negligible. The accuracy of the sensor itself is specified as 0.2 - 0.5 % FS. At a fill level of 0 - 1 meter, the 0.5 cm noise is exactly 0.5 % …

[Update] A 1 uF capacitor between ground and A0 provides some protection against noise and is included in the circuit diagram.

[Update 2] The A/D converter of the ESP8266 is not suitable for such measurements and does not work linearly. The Espressif data sheets also say this. That’s why I’m now using an ADS1115 AD converter and the noise is gone. However, I have to recapture the values and the cistern is currently full. An update on this is coming soon.

The calibrate_linear filter converts the voltage into the actual fill level, as the sensor does not work completely linearly. I determined the first values with my test setup and am now gradually correcting them with the values from the cistern. The - multiply: 100 filter ensures that the output is in centimeters.

I then query the ADC a second time to get an output in volts, which I can use to gradually correct the linear filter with the real fill levels.

The second function starts with - platform: template

Here I get the value in centimeters with return id(levelraw).state; and then convert it to the fill level in liters with another - calibrate_linear filter.

Convert fill level to volume with fill level curve
#

My Rewatec cistern has a rather complex shape, so the fill levels in liters are not linear over the fill level. Rewatec sent me a fill level curve on request. This allows the fill level to be converted depending on the fill level. As mentioned before: With 5,000 liters, it doesn’t matter whether 20 liters more or less are displayed. The rest is just an auxiliary function that can be omitted.

At the moment it is also very dry here, so the water level in the cistern is at a very low level of 10 - 25 centimeters and therefore 150 - 1000 liters.

However, it is easy to see the inflow and outflow and you can use it to determine how many liters 5 minutes of lawn watering is. In our case, we get about 150 liters per watering. You can also recognize rainfall and thus the rather rapid increase in the level.

As we also have two recessed and connected rain barrels with 1,500 liters each, I will also install a sensor here soon.

Overall, the solution with the TL-136 liquid level transmitter is a simple and sufficiently accurate solution for measuring liquid levels. The sensors are robust and easy to control. They can be easily corrected with the linear filters of the ESPHome platform, so that an accuracy in the range of 1 % is possible. This is more than sufficient for use in rainwater barrels and cisterns.

The values obtained can be used to dynamically control the watering duration, for example, to shorten the watering time when there is only a little water left in the cistern.

Update 2023 - more reliable and accurate measurement
#

As announced last year, I have optimized the water level sensor. The problem with the original project was the poor ADC of the ESP8266, which was very noisy. In addition, the circuit with the simple measuring resistor was not particularly reliable, which was also correctly noted here in the comments. Due to the winter season and other projects, the update took a little longer than planned.

As already described, I now have an ADS1115 4-channel ADC in use. You only need one of the 4 channels of the ADS1115, so you still have 3 ADCs left for other tasks.

After a few tests, I also opted for the inexpensive current transformer / transducer . This small module not only has the advantage that the input of the ADS1115 never sees more than 3.3 volts. To do this, remove all the jumpers on the module. You can also set the zero point (sensor not immersed) and the maximum output voltage. This allows you to maximize the measuring range, even if you only have to measure up to a maximum of 70 cm with a 0-1 meter sensor, for example. I have desoldered the terminals so that I can solder the module to my strip grid board.

Following a tip in the comments, I had to refresh my knowledge of 4-20 mA current loops (that was almost 30 years ago and I no longer had it to hand): These current loops are very robust against interference and can be 100 m or more long. This allows the TL136 sensor to be extended into the house, where the associated electronics are installed in a warm and dry place

The wiring is very simple. The ADS1115 is connected to the Wemos via I2C bus, the output of the transducer is connected to an input (ADC0 in my case) of the ADS1115.

Use the trimmer labeled “Zero” in the circuit diagram to set the output voltage of the module (green cable in the diagram) to almost 0 volts when the sensor is not immersed. Now immerse the TL136 sensor to the maximum depth at the maximum fill level and set the voltage at the output (green cable in the diagram) to just under 3.3 volts using the “Span” trimmer. This makes optimum use of the possible measuring range and gives the maximum resolution.

I took another series of measurements in 10 cm increments and noted the corresponding tensions. As before, this is used to calculate the filling height in centimeters and from this the filling quantity according to the manufacturer’s filling diagram.

Thanks to the transducer and the ADS1115, you are rewarded with a very precise (although already exaggerated accuracy for the application) and noise-free measurement. The residual noise is a maximum of 0.1 % and thus corresponds to the tolerance of the TL136 sensor.

Here is a comparison of the old method with the new one, which probably speaks for itself:

If you zoom in closely, you can see that the deviation is now only +- 1mm:

The remaining ADC channels of the ADS1115 can be used for simple soil moisture sensors etc., for example.

As there were still GPIOs free on the Wemos anyway, I also provided an input for 1-wire sensors. The inexpensive DS18B20 temperature sensors can be used, for example, to measure the floor temperature, the temperature in the shed or the water temperature in the cistern. Several of these 1-wire sensors can be operated in parallel at one input.The remaining ADC channels of the ADS1115 can be used for simple soil moisture sensors etc., for example.As there were still GPIOs free on the Wemos anyway, I also provided an input for 1-wire sensors. The inexpensive DS18B20 temperature sensors can be used, for example, to measure the floor temperature, the temperature in the shed or the water temperature in the cistern. Several of these 1-wire sensors can be operated in parallel at one input.

Part list:
#

The new code with ADS1115 and 1-wire (the 1-wire circuit is not included in the circuit diagram - you can do that yourself if you need it ;-) !) looks like this in my case:

esphome:
  name: zisterne
  platform: ESP8266
  board: d1_mini

# Enable logging
logger:
  baud_rate: 0

# Enable Home Assistant API
api:

ota:
  password: !secret ota_password

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  use_address: zisterne.local

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Waterking Fallback Hotspot"
    password: !secret fallback_password

captive_portal:

# i2c Bus auf D1 und D2 konfigurieren
i2c:
  id: bus_a
  sda: D2
  scl: D1
  scan: True

# 1-Wire-Sensoren am Pin D4
dallas:
  - pin: D4

# Setup ADC, ADDR-Pin is on VCC potential, therefore address 0x49 is used
ads1115:
  - address: 0x49
    id: ads1115_49

# ADC channel A0 for measured value acquisition
sensor:
  - platform: ads1115
    multiplexer: 'A0_GND'
    gain: 4.096
    name: "Waterlevel cistern in cm"
    id: levelraw
    update_interval: 2s
    unit_of_measurement: cm
    accuracy_decimals: 1
    icon: "mdi:car-coolant-level"
# Smoothing measured values:
    filters:
      - sliding_window_moving_average:
          window_size: 20
          send_every: 20
# Convert voltages to fill level according to measurement series
      - calibrate_linear:
          - 0.0 -> 0.0
          - 0.3 -> 10
          - 0.69 -> 20
          - 1.0 -> 30
          - 1.35 -> 40
          - 1.75 -> 50
          - 2.03 -> 60
          - 2.42 -> 70
          - 2.7 -> 80
          - 3.1 -> 90

# Calculate fill quantity according to fill level curve

  - platform: template
    name: "Cistern liters"
    lambda: |-
      return id(levelraw).state;

    filters:
      - calibrate_linear:
          - 4 -> 80
          - 10 -> 200
          - 12.5 -> 300
          - 15 -> 400
          - 17.5 -> 500
          - 20 -> 600
          - 25 -> 850
          - 27.5 -> 1000
          - 40 -> 1700
          - 45 -> 2000
          - 60 -> 3000
          - 70 -> 3600
          - 80 -> 4000
          - 85 -> 4400
          - 90 -> 4700
          - 95.5 -> 4980

    unit_of_measurement: l
    accuracy_decimals: 0

# 1-Wire Temperaturesensor

  - platform: dallas
    address: 0xef0516905a21ff28
    name: "Cistern Watertemp"
    unit_of_measurement: °C
    accuracy_decimals: 1

If you wish, you can also connect a display to show the water level, temperature etc. via the I2C bus or the Wemos SPI bus pins D5, D6 and D7. A LC display of type 1602/HD44780 or a MAX7219 7-segment display are suitable here. I also use the latter in my irrigation controller “Waterking” , which also displays the water level in the cistern.

Verwandte Artikel

Wasserstand in Zisternen mit HomeAssistant, ESPHome und TL-136 Drucksensor messen - UPDATE!
·12 min
Feature Smarthome Diy Esphome Garten Home-Assistant Wemos
Mit einem TL-136 Drucksensor, ESPHome und Home Assistant kann man den Füllstand von Zisternen, Tanks und Regentonnen sehr einfach und genau messen.
DIY Bewässerungssteuerung mit Home Assistant und ESPHome
·13 min
Feature Smarthome Diy Esp8266 Esphome Garten Home-Assistant Wemos
Das ist meine DIY-Hardware für die Steuerung von 24 Volt Bewässerungsventilen
Mein neuer ESPHome Multisensor mit Display für Home Assistant
·18 min
Smarthome Diy Esp8266 Esphome Home-Assistant Smart-Home Wemos
Ich habe mit ESPHome und ein paar Komponenten einen umfangreichen Multisensor für 1-Wire, I2C und SPI gebaut, der sogar ein mehrseitiges Menü mit Display hat.