- • ESP32-C3
- • ESPHome
- • Home Assistant
With a TL-136 pressure sensor (4-20 mA), an ADS1115 16-bit ADC and **
ESPHome ESPHomeFramework for configuring ESP32/ESP8266 microcontrollers that automatically integrate into Home Assistant. Ideal for DIY sensors and actuators **, you can measure the water level of your cistern, rain barrel or IBC container to **±1 mm** — for under $60. This guide covers the complete build: hardware, ESP32 ESP32Microcontroller by Espressif with integrated Wi-Fi and Bluetooth. The heart of many DIY smart home projects – programmable via ESPHome, Tasmota or Arduino -C3 code and calibration.Rainwater is now a precious commodity — and if you have your own cistern or rain barrel, you want to know how much water is in it. A reliable cistern water level sensor is therefore the first step towards smart irrigation. Last year we got a 5,000 litre rainwater cistern from Rewatec . It’s rarely worth having something like this installed just for the rainwater, as the effort and costs are considerable.
⚠ [affiliate] Keine Produkte mit Cache für home-assistant.
Bitte affiliate-sync --lang en ausführen.

However, when renovating our patio, we realised that our guttering was dilapidated and the digger was already there anyway, so the cistern could be installed with little effort. The rain that falls on the 75 square metres of the 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 5-7 years). Of course, we want to know how much water is in the cistern so that we can then control the irrigation. In addition, the submersible pump needs a minimum fill level of 8 cm so that it does not run dry.
DIY solutions usually unreliable
If you want to measure the water level in your cistern, you’ll find many DIY approaches online — most work rather poorly. Ultrasonic sensors that are aimed 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.

Using a float to measure the cistern water level, for example via a cascade of reed relays and resistors with a magnet float, works well and is robust — but only has a very coarse resolution. This is rather unsatisfactory for a cistern that can reach a maximum level of 1.05 metres.
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
For precise cistern level measurement, piezoelectric pressure sensors are the best choice — not quite as inexpensive, but robust and accurate. The TL-136 liquid level transducer is a great option. 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 metre model as the overflow of my cistern is already at 105 cm. The 0-1 metre model should also be suitable for the popular IBC containers, as you don’t let them fill up to the last centimetre.

The sensor is supplied with 24 volts and converts the pressure in the range 0-20 mA. The current must therefore be measured in order to calculate the fill level and later the fill quantity. A 4-20mA sensor connected to a Wemos D1 or ESP32-C3 is easy to wire up. 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, you can tap the range up to 100 cm in such a way that it becomes a voltage with a maximum of 3.2 volts - ideal for the ADC of an ESP8266 or ESP32. With a 27 kOhm resistor in series to the analogue 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 no need to use an additional power supply for the sensor’s 24 volts. A step-up converter does the job 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.
The LM2596 is a step-DOWN converter (it lowers the voltage). For 24 V from 5 V you need a step-UP converter such as the XL6009. Anyone who installs an LM2596 will never get more than 5 V at the sensor — a common mistake reported by several readers.
If you have a 24-V wall adapter (~$6) at hand, that’s the simpler and less noisy option. The XL6009 boost is compact, but some readers reported instability and noise. Both paths work — with an external 24-V PSU you save yourself a potential source of error.

To find out which voltage is output at which 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 litre cistern.

The electronics: ADS1115 and ESPHome
Even the ESP32-C3 only has a 12-bit SAR ADC, which is not suitable for precise DC measurements — it is noisy and non-linear at low voltages. The ADS1115 is a 16-bit sigma-delta converter and provides the resolution needed for ±1 mm fill level. The ADS1115 is therefore not a workaround for a poor ESP8266 ADC, but the actual precision solution — regardless of which ESP you use.
The code for the ESPHome sensor is fairly self-explanatory. The analogue-digital converter is read out. The id: levelraw allows me to access the level in centimetres again later in another function. In the tabs you’ll find the configuration for ESP32-C3 (recommended) and ESP8266/Wemos D1 (alternative for existing setups):
|
|
|
|
The calibrate_linear filter converts the voltage into the actual fill level, because the sensor is not completely linear. The formula for the water level from the voltage is therefore not simply “voltage × factor”, but is interpolated over the measured characteristic curve of the sensor — that’s exactly what calibrate_linear does for you. I have 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 centimetres.

The filters (sliding_window_moving_average, median) are also the answer to the common question of how to clean up measured values in Home Assistant: instead of smoothing afterwards in Home Assistant, ESPHome does it directly on the microcontroller — the values arrive clean. I then query the ADC a second time to obtain 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 centimetres with return id(levelraw).state; and then convert it to the fill level in litres with another - calibrate_linear filter.
Historical ESP8266 ADC code (deprecated)
This code uses the A0 ADC of the ESP8266, which is not suitable for such measurements (noise, non-linearity). It is shown for documentation purposes only — use the ADS1115 code above instead.
The code for the ESPHome sensor is fairly self-explanatory. The A0 pin, i.e. the analogue-digital converter, is read out. Incidentally, the ESP8266 does not output 0 - 3.3 volts here, but 0 - 1 V. I have therefore installed a filter with - multiply: 3.3. The id: levelraw allows me to access the level in centimetres again later in another function.
|
|
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 metre, the 0.5 cm noise is exactly 0.5 % …
ESP32-C3 instead of ESP8266: why?
Since 2026 I recommend an ESP32-C3 for new projects instead of the classic Wemos D1 Mini (ESP8266). The price difference is minimal, but the advantages are significant:
| ESP8266 (Wemos D1) | ESP32-C3 | |
|---|---|---|
| Price | ~$3 | ~$3–6 |
| Architecture | Xtensa (2014) | RISC-V (2021) |
| RAM | 80 KB | 400 KB |
| WiFi | 2.4 GHz b/g/n | 2.4 GHz + BLE BLEBluetooth Low Energy – energy-efficient Bluetooth variant for sensors. Xiaomi Mijia temperature sensors and hygrometers use BLE, for example 5 |
| ADC | 10-bit (inaccurate) | 12-bit (better, but ADS1115 still needed) |
| Toolchain | PlatformIO | ESP-IDF (default since ESPHome 2026.7) |
| Future-proof | Barely developed further | Actively maintained by Espressif |
Can I keep using my old Wemos D1 Mini? Yes, absolutely — the configuration in the second tab uses exactly the same sensors and filters, just with a different pin assignment (D1/D2 instead of GPIO). For an existing, running system the rebuild is not worth it. For new builds, however, the ESP32-C3 is clearly the better choice — especially because ESPHome and Espressif only maintain the ESP8266, but no longer actively develop it.
Convert filling height to volume with level curve
My Rewatec cistern has a rather complex shape, so the fill levels in litres are not linear over the fill level. Rewatec sent me a fill level curve on request. This allows the fill level to be converted as a function of the fill level. As mentioned before: With 5,000 litres, it doesn’t matter whether 20 litres more or less are displayed. The rest is just an auxiliary function that can be omitted.
Monitoring the cistern fill level via app is easy: with the
Home Assistant Companion App
you always have the value sensor.cistern_litres in your pocket — including history, notifications and dashboard cards. If you use Apple Home (HomeKit), you can expose the sensor via the
HomeKit Bridge
and show the fill level as a water level sensor in the Apple Home app.

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 centimetres and therefore 150 - 1000 litres.

However, you can easily see the inflows and outflows and can therefore also determine how many litres 5 minutes of lawn watering is. In our case, we get about 150 litres per watering. You can also easily recognise rainfall and the rapid rise in the level.

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

Overall, the solution with the TL-136 liquid level transmitters is a simple and sufficiently accurate solution for measuring fill 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.
Questions or your own experiences? Feel free to leave a comment — I (nachbelichtet) regularly answer questions about cistern monitoring here and have since extended the build to two rain barrels as well.

The values obtained can be used to dynamically control the watering time, for example by shortening 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 optimised 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 am now using an ADS1115 4-channel ADC. 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 decided in favour of 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. All jumpers on the module are removed for this purpose. You can also set the zero point (sensor not immersed) and the maximum output voltage. This allows you to maximise the measuring range, even if you only have to measure up to a maximum of 70 cm with a 0-1 metre 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 means you can extend the TL136 sensor 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.

Using the trimmer labelled “Zero” in the circuit diagram, 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 again took a series of measurements in 10 cm steps and noted the corresponding voltages. As before, this is used to calculate the filling height in centimetres 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 excessive 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:


Zoomed in sharply, you can see that the deviation is now only - 1mm:

The remaining ADC channels of the ADS1115 can be used, for example, for simple soil moisture sensors etc.
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 record the ground 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.

How to calibrate the sensor
The calibrate_linear values in the code are only a starting point — every sensor and build varies slightly. To determine your own measurement series, all you need is an HT pipe and water:
- Set up an HT pipe (100 mm) with an end cap vertically and fill it with water. The hydrostatic pressure in a water column is independent of the diameter — so the pressure in the pipe is the same as in a 5,000-litre cistern.
- Attach the TL-136 to a string and immerse it in defined steps (0 cm, 10 cm, 20 cm … up to the maximum fill level).
- Note the voltage — either in the ESPHome log (
sensor.cistern_volt) or directly with a multimeter at the transducer output. - Enter the value pairs in
calibrate_linear:- <voltage> -> <fill level>. ESPHome interpolates linearly between the measurement points — 10-cm steps are perfectly sufficient. - Re-adjust after installation: once the cistern has a known fill level (e.g. empty or at a known quantity), correct the two end points of the curve.
Before taking the measurement series, use the “Zero” and “Span” trimmers of the transducer to set the zero point (sensor not immersed) and the end voltage (sensor at maximum depth) to just under 0 V and just under 3.3 V respectively — this makes optimum use of the ADS1115’s measuring range.
Parts list:
- 1x ESP32-C3 SuperMini (recommended; the Wemos D1 Mini also works, but with different pins)
- 1x step-up (boost) converter XL6009 (NOT the LM2596 — that’s a step-down!)
- 1x ADS1115 ADC module
- 1x 4-20mA transducer
- 1x TL-136 sensor with the required maximum fill level
Full ADS1115 code for ESP8266 / Wemos D1 (historical)
This configuration was my state from 2023 onwards — ADS1115 with ESP8266. The code in the tabs above is the modernised version for ESP32-C3 (2026). The 1-wire circuit is not included in the circuit diagram — you can do it yourself if you need it ;-)
The new code with ADS1115 and 1-Wire looks like this for me:
|
|
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. An LC display of type 1602/HD44780 or a MAX7219 7-segment display are suitable here. I also use the latter in my “Waterking” irrigation controller , which also displays the water level in the cistern.
Alternative: INA219 instead of transducer + ADS1115
A reader (Adrian) suggested a neat alternative: instead of the 4-20-mA transducer plus ADS1115, the
INA219
measures the current directly via I²C — with a 10-ohm shunt and platform: ina219 in ESPHome:
|
|
Advantage: saves two components (transducer + ADS1115) and simplifies the wiring. Disadvantages: no zero/span adjustment for the optimum measuring range, no galvanic isolation, different accuracy characteristics. If you want to use the measuring range precisely, stick with the ADS1115 build.
Experiences from the community
This is one of the most-read posts on fricklr — many readers have rebuilt the project and shared their experiences:
- PCB: Marc designed his own PCB for the build — perfect if you want a compact, clean board instead of a breadboard or stripboard.
- 3D-printed enclosure: Jörg designed a matching enclosure into which the components fit exactly.
- IBC container with frost protection: Carsten uses the build for an above-ground 600-litre IBC tank and added temperature monitoring plus a pond heater against freezing.
- Display on the I²C bus: Flosi connected a 20x4 LCD and shows voltage, fill level and litres directly on the device — including a button for the backlight.
Known stumbling blocks
- USB power supply quality: some readers reported irregular restarts. The cause was usually a cheap USB power supply that collapses under load. A quality supply (or a capacitor at the 5-V input) fixes this.
- Protective fuse blows: if a 250-mA fuse between the power supply and the circuit keeps blowing, check the wiring for an intermittent short — often the weak point in rebuilt circuits.
- Temperature drift: fluctuating readings over the day despite a constant fill level indicate temperature-sensitive electronics in an unheated enclosure (details in the FAQ).
Frequently asked questions about cistern level measurement
Can I extend the sensor with a long cable?
Yes. The 4-20-mA current loop is very robust against interference and can easily span 100 metres or more. You can use any suitable low-voltage cable (e.g. 18 AWG) to extend the TL-136 into the house, where the electronics are installed dry.
Why LM2596 and not XL6009?
The LM2596 is a step-DOWN converter (it lowers the voltage). For 24 V from 5 V you need a step-UP converter such as the XL6009. Anyone who installs the LM2596 will never get more than 5 V at the sensor — a common pitfall.
How accurate is the measurement?
With the ADS1115 and the transducer, the deviation is ±1 mm fill level. The residual noise is a maximum of 0.1 % and corresponds to the tolerance of the TL-136 sensor (0.2–0.5 % FS).
Does it work with IBC containers too?
Yes, very well. For an IBC container (typically 600–1000 litres) the 0-1-metre model of the TL-136 is suitable, as these are usually not filled to the very last centimetre. Several readers confirm this after rebuilding the project for their IBC tanks.
Which measuring range should the TL-136 have?
Choose a range as close as possible to the maximum fill height (e.g. 0–1 m instead of 0–3 m). An oversized sensor works without damage but noticeably worsens the reading: at 0.5 % FS the absolute error triples (with 0–3 m: ±1.5 cm instead of ±0.5 cm), and you only use a third of the 4-20-mA signal range — the ADC loses two thirds of its resolution. Temperature drift also affects you three times as much.
Can I use an ESP32 instead of the ESP8266?
Yes — in 2026 this is even the recommended choice. An ESP32-C3 costs barely more than a Wemos D1 Mini, has more RAM/flash and uses the modern ESP-IDF toolchain. The pin assignment is different (GPIO numbers instead of D1/D2), the rest of the code remains the same.
What to do about temperature drift?
If the fill level drifts over the day with a constant water level, the electronics in an unheated enclosure is usually temperature-sensitive. Place the transducer and ADS1115 somewhere dry and temperature-stable (e.g. in the house) and extend the 4-20-mA cable.
How do I prevent a short circuit in the cistern?
The 4-20-mA current loop is high-impedance and short-circuit-proof — no high currents flow in the event of a short circuit. The transducer input usually tolerates this. A polyswitch element at the ESP input provides additional protection.
Which update interval do I need for pump control?
For pure display, the standard ~40 seconds is enough (window_size: 20, send_every: 20 at 2s interval). If you control a pump, reduce it to window_size: 5, send_every: 5 — then you have ~10 seconds of freshness.
What do you think? Leave a comment!
Share your thoughts, questions or experiences with the community.