Water Pressure Sensor to measure tank volume assistance

HI all,

I apologise for the long post but I’ve noticed that there are so many threads on water level sensors so I’m not quite sure which one I should post my questions to, hence the new topic. I was wondering if someone could assist me.

As per the diagram below, I’m planning on installing a DF Robot Analog Pressure Sensor on the lower outlet pipe of our 2400 L water storage tank.
The tanks dimensions are Height: 1700mm. Diameter: 1420mm

The other components that I plan to use include:

The tank is currently empty so I would like to try and calibrate it every 100L as I have a flow gauge on the garden hose which I plan to use to fill the tank. I’m planning on initially using the code below to get the Voltage reading every 100L until the tank is full.

  - platform: adc
    pin: A0
    name: "water pressure"
    update_interval: 2s
    unit_of_measurement: "V"

Once I have these readings, I’d like to use this as my main code to display Liters as well as a % of how full the tank is (I’ll update the voltages and water levels from the readings obtained above):

  - platform: adc
    pin: A0
	name: "water volume"
	update_interval: 2s
	unit_of_measurement: 'l'
	icon: "mdi:gauge"
	accuracy_decimals: 1
    min: 0
    max: 2400
      - median: 
        window_size: 200
        send_every: 10
        send_first_at: 4
	  - calibrate_linear:
       - voltage: 0.3
        water_level: 0
       - voltage: 0.6
        water_level: 100
       - voltage: 0.9
        water_level: 200
       - voltage: 1.2
        water_level: 300
       - voltage: 1.5
        water_level: 400
       - voltage: 1.8
        water_level: 500
       - voltage: 2.1
        water_level: 600
       - voltage: 2.4
        water_level: 700
       - voltage: 2.7
        water_level: 800
       - voltage: 3.0
        water_level: 900
       - voltage: 3.3
        water_level: 1000
       - voltage: 3.6
        water_level: 1100
  unit_of_measurement: '%'
  value_template: '{{ ((states.sensor.pressure_sensor.state | float) / 2400) * 100 | round(2) }}'
  icon: mdi:percent
- name: Pressure Sensor
    - sensor.pressure_sensor
    - sensor.pressure_sensor_percentage

Please could you kindly confirm if I need to add in an additional filter to account for the voltage divider which this board apparently has but I’m not sure if this is necessary as I’m powering the sensor from a separate power supply or am I totally confused?

 - platform: adc
    - multiply: 3.3

If so, do I need to use this to obtain the initial Voltage reading and then again for my main code?

I’m happy to use any other suggestions that you may have but I really appreciate you reading this :grinning:

Many thanks,


Hi Martin.

Did you get this to work? I’m interested in doing the same.

Hi there,
This was a terrible solution as there were too many inaccuracies and variations for no apparent reason.

Please see post of mine with details of what I’m currently using:

Some of the other ESP32 + sensor solutions which I’ve tried and given up on:

  • Waterproof ultrasonic sensor - difficult to implement as the minimum distance between the sensor and the water level is ±20CM if I recall correctly. This meant that I would need to 3D print a cone to raise the ultrasonic sensor and cut a large hole in the Jojo Tank. Plus the issues of condensation on the sensor.
  • Analog water pressure sensor - this was attached to the bottom of the outlet of the tank. The readings were all over the place and I’d see random drops for no apparent reason so I gave up on this.
  • Throw in pressure sensor + ADS1115 A/D Module + voltage regulation - this was probably the longest standing solution that I had in place. The results were very erratic and I’d see random fluctuations for no apparent reason. Landed up having to re-calibrate multiple times - definitely something was wrong.

After advice from others on the Home Assistant Forum, I tried a solution which was suggested by others and it’s been spot on and much easier to implement!



2 Measurements were taken to calibrate:

  • 1: when the sensor was not inside the tank
  • 2: when the sensor was in the tank and the tank was full (manual float switch had stopped filling).

As seen in the code below:

float full_voltage = 0.00092; // Voltage at full condition
float empty_voltage = 0.00042; // Voltage at empty condition


float max_full_reading = 9.2; // Adjust the maximum reading at full water level
float min_empty_reading = 4.2; // Adjust the minimum reading at empty water level

As there are 2 tanks and only 1 sensor, the total volume is multiplied by 2.

Both tank levels equalize when they’re full and are thus same.



  sda: 21
  scl: 22

  - platform: ina219
    address: 0x40
    shunt_resistance: 0.1 ohm
      name: "INA219 Current"
      id: ina_current
      accuracy_decimals: 5
      - multiply: 1000 #convert from Amps to mA
      unit_of_measurement: "mA"
      name: "INA219 Power"
      accuracy_decimals: 5
      name: "INA219 Bus Voltage"
      accuracy_decimals: 2
      name: "INA219 Shunt Voltage"
      id: ina219_shunt_voltage
      accuracy_decimals: 5
    max_voltage: 32.0V
    max_current: 400mA
    update_interval: 10s

  - platform: template
    name: "Water Level"
    id: water_level
    unit_of_measurement: 'm'
    accuracy_decimals: 3
    update_interval: 60s
    lambda: |-
      float shunt_voltage = id(ina219_shunt_voltage).state;
      float full_voltage = 0.00092; // Voltage at full condition
      float empty_voltage = 0.00042; // Voltage at empty condition
      float max_height = 1.570; // Adjust the max height as needed

      // Calculate water level based on calibration
      float slope = (max_height - 0.0) / (full_voltage - empty_voltage);
      float intercept = max_height - slope * full_voltage;
      float water_level = slope * shunt_voltage + intercept;

      // Ensure water level is within bounds
      water_level = water_level < 0.0 ? 0.0 : water_level;
      water_level = water_level > max_height ? max_height : water_level;

      ESP_LOGD("custom", "Shunt Voltage: %.5f V", id(ina219_shunt_voltage).state);
      ESP_LOGD("custom", "Water Level: %.5f m", water_level);
      return water_level;

  - platform: template
    name: "Current Full Percentage"
    id: current_full_percentage
    unit_of_measurement: '%'
    accuracy_decimals: 1
    update_interval: 60s
    lambda: |-
      float max_full_reading = 9.2;  // Adjust the maximum reading at full water level
      float min_empty_reading = 4.2;  // Adjust the minimum reading at empty water level
      float current_reading = id(ina_current).state;
      if (current_reading <= min_empty_reading) {
        return 0.0;
      } else if (current_reading >= max_full_reading) {
        return 100.0;
      } else {
        float current_full_percentage = 100 * (current_reading - min_empty_reading) / (max_full_reading - min_empty_reading);
        return current_full_percentage;

  - platform: template
    name: "Tank Volume"
    id: tank_volume
    unit_of_measurement: "litres"
    lambda: |-
      float tank_radius = 0.71;  // Adjust the tank radius as needed
      float max_height = 1.57;   // Adjust the max height as needed
      float total_volume_single_tank = 3.14159265 * tank_radius * tank_radius * max_height * 1000;
      float percentage_full = id(current_full_percentage).state;
      float water_level = max_height * (percentage_full / 100.0);
      float current_volume_single_tank = 3.14159265 * tank_radius * tank_radius * water_level * 1000;
      float total_volume_both_tanks = 2 * current_volume_single_tank;
      return total_volume_both_tanks;

We had a water outage today so I had an opportunity to test the sensor value (height) vs the actual height with a tape measure and I was off by 5mm, so I’ll take this as a success.



1 Like